summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/update
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:50 +0000
commitdef92d1b8e9d373e2f6f27c366d578d97d8960c6 (patch)
tree2ef34b9ad8bb9a9220e05d60352558b15f513894 /toolkit/mozapps/update
parentAdding debian version 125.0.3-1. (diff)
downloadfirefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.tar.xz
firefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/mozapps/update')
-rw-r--r--toolkit/mozapps/update/common/readstrings.cpp75
-rw-r--r--toolkit/mozapps/update/common/readstrings.h18
-rw-r--r--toolkit/mozapps/update/nsIUpdateService.idl6
-rw-r--r--toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js2
-rw-r--r--toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js2
-rw-r--r--toolkit/mozapps/update/tests/browser/head.js12
-rw-r--r--toolkit/mozapps/update/tests/data/README.md15
-rw-r--r--toolkit/mozapps/update/tests/data/complete_mac.marbin87129 -> 87143 bytes
-rw-r--r--toolkit/mozapps/update/tests/data/partial_mac.marbin10361 -> 10351 bytes
-rw-r--r--toolkit/mozapps/update/tests/data/shared.js10
-rw-r--r--toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js155
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js9
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js38
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml4
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js9
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js12
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js12
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js7
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js7
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js7
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js3
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js3
-rw-r--r--toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js3
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js6
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js2
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js7
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js7
-rw-r--r--toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js7
-rw-r--r--toolkit/mozapps/update/updater/Makefile.in3
-rw-r--r--toolkit/mozapps/update/updater/launchchild_osx.mm56
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build18
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build18
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist24
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md77
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h17
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm13
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build24
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h17
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm21
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/moz.build18
-rw-r--r--toolkit/mozapps/update/updater/moz.build3
-rw-r--r--toolkit/mozapps/update/updater/updater-common.build13
-rw-r--r--toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in4
-rw-r--r--toolkit/mozapps/update/updater/updater.cpp121
62 files changed, 705 insertions, 244 deletions
diff --git a/toolkit/mozapps/update/common/readstrings.cpp b/toolkit/mozapps/update/common/readstrings.cpp
index 17c2d002a1..28dc8ea6ff 100644
--- a/toolkit/mozapps/update/common/readstrings.cpp
+++ b/toolkit/mozapps/update/common/readstrings.cpp
@@ -38,16 +38,6 @@ class AutoFILE {
FILE* fp_;
};
-class AutoCharArray {
- public:
- explicit AutoCharArray(size_t len) { ptr_ = new char[len]; }
- ~AutoCharArray() { delete[] ptr_; }
- operator char*() { return ptr_; }
-
- private:
- char* ptr_;
-};
-
static const char kNL[] = "\r\n";
static const char kEquals[] = "=";
static const char kWhitespace[] = " \t";
@@ -153,7 +143,8 @@ int ReadStrings(const NS_tchar* path, const char* keyList,
}
size_t flen = size_t(len);
- AutoCharArray fileContents(flen + 1);
+
+ char* fileContents = new char[flen + 1];
if (!fileContents) {
return READ_STRINGS_MEM_ERROR;
}
@@ -170,12 +161,53 @@ int ReadStrings(const NS_tchar* path, const char* keyList,
fileContents[flen] = '\0';
- char* buffer = fileContents;
+ int result = ReadStringsFromBuffer(fileContents, keyList, numStrings, results,
+ section);
+ delete[] fileContents;
+ return result;
+}
+
+// A wrapper function to read strings for the updater.
+// Added for compatibility with the original code.
+int ReadStrings(const NS_tchar* path, StringTable* results) {
+ const unsigned int kNumStrings = 2;
+ const char* kUpdaterKeys = "Title\0Info\0";
+ mozilla::UniquePtr<char[]> updater_strings[kNumStrings];
+
+ int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings);
+
+ if (result == OK) {
+ results->title.swap(updater_strings[0]);
+ results->info.swap(updater_strings[1]);
+ }
+
+ return result;
+}
+
+/**
+ * A very basic parser for updater.ini taken mostly from nsINIParser.cpp
+ * that can be used by standalone apps.
+ *
+ * @param stringBuffer The string buffer to parse
+ * @param keyList List of zero-delimited keys ending with two zero
+ * characters
+ * @param numStrings Number of strings to read into results buffer - must be
+ * equal to the number of keys
+ * @param results Array of strings. Array's length must be equal to
+ * numStrings. Each string will be populated with the value
+ * corresponding to the key with the same index in keyList.
+ * @param section Optional name of the section to read; defaults to
+ * "Strings"
+ */
+int ReadStringsFromBuffer(char* stringBuffer, const char* keyList,
+ unsigned int numStrings,
+ mozilla::UniquePtr<char[]>* results,
+ const char* section) {
bool inStringsSection = false;
unsigned int read = 0;
- while (char* token = NS_strtok(kNL, &buffer)) {
+ while (char* token = NS_strtok(kNL, &stringBuffer)) {
if (token[0] == '#' || token[0] == ';') { // it's a comment
continue;
}
@@ -233,23 +265,6 @@ int ReadStrings(const NS_tchar* path, const char* keyList,
return (read == numStrings) ? OK : PARSE_ERROR;
}
-// A wrapper function to read strings for the updater.
-// Added for compatibility with the original code.
-int ReadStrings(const NS_tchar* path, StringTable* results) {
- const unsigned int kNumStrings = 2;
- const char* kUpdaterKeys = "Title\0Info\0";
- mozilla::UniquePtr<char[]> updater_strings[kNumStrings];
-
- int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings);
-
- if (result == OK) {
- results->title.swap(updater_strings[0]);
- results->info.swap(updater_strings[1]);
- }
-
- return result;
-}
-
IniReader::IniReader(const NS_tchar* iniPath,
const char* section /* = nullptr */) {
if (iniPath) {
diff --git a/toolkit/mozapps/update/common/readstrings.h b/toolkit/mozapps/update/common/readstrings.h
index 9e0ebbefb5..8fa8a49756 100644
--- a/toolkit/mozapps/update/common/readstrings.h
+++ b/toolkit/mozapps/update/common/readstrings.h
@@ -24,6 +24,15 @@ struct StringTable {
mozilla::UniquePtr<char[]> info;
};
+struct MARChannelStringTable {
+ MARChannelStringTable() {
+ MARChannelID = mozilla::MakeUnique<char[]>(1);
+ MARChannelID[0] = '\0';
+ }
+
+ mozilla::UniquePtr<char[]> MARChannelID;
+};
+
/**
* This function reads in localized strings from updater.ini
*/
@@ -38,6 +47,15 @@ int ReadStrings(const NS_tchar* path, const char* keyList,
const char* section = nullptr);
/**
+ * This function reads in localized strings corresponding to the keys from a
+ * given string buffer.
+ */
+int ReadStringsFromBuffer(char* stringBuffer, const char* keyList,
+ unsigned int numStrings,
+ mozilla::UniquePtr<char[]>* results,
+ const char* section = nullptr);
+
+/**
* This class is meant to be a slightly cleaner interface into the ReadStrings
* function.
*/
diff --git a/toolkit/mozapps/update/nsIUpdateService.idl b/toolkit/mozapps/update/nsIUpdateService.idl
index ab1712587c..972d0f4f55 100644
--- a/toolkit/mozapps/update/nsIUpdateService.idl
+++ b/toolkit/mozapps/update/nsIUpdateService.idl
@@ -380,7 +380,7 @@ interface nsIApplicationUpdateService : nsISupports
* check starting does not necessarily mean that the check will
* succeed or that an update will be downloaded.
*/
- bool checkForBackgroundUpdates();
+ boolean checkForBackgroundUpdates();
/**
* Selects the best update to install from a list of available updates.
@@ -654,7 +654,7 @@ interface nsIUpdateProcessor : nsISupports
* @throws NS_ERROR_NOT_IMPLEMENTED
* If this is called on a non-Windows platform.
*/
- bool getServiceRegKeyExists();
+ boolean getServiceRegKeyExists();
/**
* Attempts to restart the application manually on program exit with the same
@@ -724,7 +724,7 @@ interface nsIUpdateSyncManager : nsISupports
* Returns whether another instance of this application is running.
* @returns true if another instance has the lock open, false if not
*/
- bool isOtherInstanceRunning();
+ boolean isOtherInstanceRunning();
/**
* Should only be used for testing.
diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js
index 07e7bf51fa..0ca510cfcf 100644
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js
@@ -64,7 +64,7 @@ add_task(async function doorhanger_bc_multiUpdate() {
is(
PanelUI.menuButton.getAttribute("badge-status"),
- "",
+ null,
"Should not have restart badge during staging"
);
diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js
index 00c61bcbb4..8012250f36 100644
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js
@@ -74,7 +74,7 @@ add_task(async function doorhanger_bc_multiUpdate() {
is(
PanelUI.menuButton.getAttribute("badge-status"),
- "",
+ null,
"Should not have restart badge during staging"
);
diff --git a/toolkit/mozapps/update/tests/browser/head.js b/toolkit/mozapps/update/tests/browser/head.js
index c5acdad8e4..b606331fd3 100644
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -368,9 +368,15 @@ function copyTestUpdater(attempt = 0) {
testUpdater.copyToFollowingLinks(greBinDir, FILE_UPDATER_BIN);
let greDir = getGREDir();
- let updateSettingsIni = greDir.clone();
- updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
- writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
+
+ // On macOS, update settings is a Framework, not an INI. This was already
+ // built into updater-xpcshell using the `UpdateSettings-xpcshell`
+ // Framework, so we don't need to do any additional work here.
+ if (AppConstants.platform != "macosx") {
+ let updateSettingsIni = greDir.clone();
+ updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
+ writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
+ }
let precomplete = greDir.clone();
precomplete.append(FILE_PRECOMPLETE);
diff --git a/toolkit/mozapps/update/tests/data/README.md b/toolkit/mozapps/update/tests/data/README.md
new file mode 100644
index 0000000000..52a7e9a5b7
--- /dev/null
+++ b/toolkit/mozapps/update/tests/data/README.md
@@ -0,0 +1,15 @@
+README
+======
+
+I needed to make changes to some of the test MARs in this directory and it was a bit difficult to figure out how, so I want to document what I did so that this is easier next time. In my specific case, I wanted to rename some files in several MARs. These are approximately the steps I used to make changes to `partial_mac.mar`:
+
+ - `./mach build` so that `<obj>/dist/bin/signmar` is available.
+ - We want use the [Python MAR tool](https://github.com/mozilla-releng/build-mar) to build the replacement MAR, but it currently has a problem that we need to fix before we can build a MAR that will allow tests to pass on Apple silicon. Once [this issue](https://github.com/mozilla-releng/build-mar/issues/63) is addressed, we can just use `pip install mar`. Until then, we need to checkout the project and tweak it before we use it. First clone the repository: `cd ~ && git clone https://github.com/mozilla-releng/build-mar`. Next, we want to remove [this line](https://github.com/mozilla-releng/build-mar/blob/2d37c446015b97d6f700fef5766a49609bdc22ea/src/mardor/utils.py#L158). Then make the tweaked version available with `cd ~/build-mar && virtualenv mardor && source mardor/bin/activate && pip install .`.
+ - Made a temporary working directory: `cd /path/to/mozilla/repo && mkdir temp && cd temp`
+ - Extracted the MAR that I wanted to change: `mar -J -x ../toolkit/mozapps/update/tests/data/partial_mac.mar`. The `-J` specifies a compression type of `xz`. You can also specify `--auto` to automatically detect the compression type (though you may want to know the original compression later for recompression) or you can check the compression type by running `mar -T ../toolkit/mozapps/update/tests/data/partial_mac.mar` and looking for the `Compression type:` line.
+ - Made the changes that I wanted to make to the extracted files. This included moving the old files to their new locations and updating those paths in `updatev2.manifest` and `updatev3.manifest`.
+ - Run `mar -T ../toolkit/mozapps/update/tests/data/partial_mac.mar` to get a complete list of the files originally in that MAR as well as the product/version and channel strings (in this case `xpcshell-test` and `*` respectively).
+ - Create the new MAR: `mar -J -c partial_mac_unsigned.mar -V '*' -H xpcshell-test <file1> <file2> ...`, individually specifying each file path listed in by `mar -T`, substituting with renamed paths as necessary.
+ - I had a bit of trouble figuring out the signing. Eventually I discovered the following things: (a) The test MAR signatures successfully verify against `toolkit/mozapps/update/updater/xpcshellCertificate.der` and (b) according to [this comment](https://searchfox.org/mozilla-central/rev/fc00627e34639ef1014e87d9fa24091905e9dc5d/toolkit/mozapps/update/updater/moz.build#41-43), that certificate was generated from `mycert` in `modules/libmar/tests/unit/data`. Thus, I signed the MAR like this: `../<obj>/dist/bin/signmar -d ../modules/libmar/tests/unit/data -n mycert -s partial_mac_unsigned.mar partial_mac.mar`.
+ - I wanted to do some verification to make sure that the new MAR looked right. First I verified the signature: `../<obj>/dist/bin/signmar -D ../toolkit/mozapps/update/updater/xpcshellCertificate.der -v partial_mac.mar`. This appears to output nothing on success, but it's probably good to check to make sure `echo $?` is `0`. I also compared the output of `mar -T partial_mac.mar` to that of the original. I saw a few unexpected size changes which I believe are likely due to slight differences in the compression used (maybe the algorithm changed slightly since this was last generated?). To make sure that these did not correspond to effective changes, I extracted the new MAR with `mkdir cmp && cd cmp && mar -J -x ../partial_mac.mar && cd ..` and compared the resulting files to make sure they had the expected contents.
+ - Overwrite the original MAR with the new one and remove the `temp` directory: `cd .. && mv -f temp/partial_mac.mar toolkit/mozapps/update/tests/data/partial_mac.mar && rm -rf temp`
diff --git a/toolkit/mozapps/update/tests/data/complete_mac.mar b/toolkit/mozapps/update/tests/data/complete_mac.mar
index c54088610a..f4603f1eef 100644
--- a/toolkit/mozapps/update/tests/data/complete_mac.mar
+++ b/toolkit/mozapps/update/tests/data/complete_mac.mar
Binary files differ
diff --git a/toolkit/mozapps/update/tests/data/partial_mac.mar b/toolkit/mozapps/update/tests/data/partial_mac.mar
index bcc04b9939..9b17747e43 100644
--- a/toolkit/mozapps/update/tests/data/partial_mac.mar
+++ b/toolkit/mozapps/update/tests/data/partial_mac.mar
Binary files differ
diff --git a/toolkit/mozapps/update/tests/data/shared.js b/toolkit/mozapps/update/tests/data/shared.js
index 60de6feeb8..e8553f7273 100644
--- a/toolkit/mozapps/update/tests/data/shared.js
+++ b/toolkit/mozapps/update/tests/data/shared.js
@@ -71,17 +71,20 @@ const FILE_ACTIVE_UPDATE_XML = "active-update.xml";
const FILE_ACTIVE_UPDATE_XML_TMP = "active-update.xml.tmp";
const FILE_APPLICATION_INI = "application.ini";
const FILE_BACKUP_UPDATE_CONFIG_JSON = "backup-update-config.json";
-const FILE_BACKUP_UPDATE_LOG = "backup-update.log";
const FILE_BACKUP_UPDATE_ELEVATED_LOG = "backup-update-elevated.log";
+const FILE_BACKUP_UPDATE_LOG = "backup-update.log";
const FILE_BT_RESULT = "bt.result";
-const FILE_LAST_UPDATE_LOG = "last-update.log";
+const FILE_CHANNEL_PREFS =
+ AppConstants.platform == "macosx" ? "ChannelPrefs" : "channel-prefs.js";
const FILE_LAST_UPDATE_ELEVATED_LOG = "last-update-elevated.log";
+const FILE_LAST_UPDATE_LOG = "last-update.log";
const FILE_PRECOMPLETE = "precomplete";
const FILE_PRECOMPLETE_BAK = "precomplete.bak";
const FILE_UPDATE_CONFIG_JSON = "update-config.json";
-const FILE_UPDATE_LOG = "update.log";
const FILE_UPDATE_ELEVATED_LOG = "update-elevated.log";
+const FILE_UPDATE_LOG = "update.log";
const FILE_UPDATE_MAR = "update.mar";
+const FILE_UPDATE_SETTINGS_FRAMEWORK = "UpdateSettings";
const FILE_UPDATE_SETTINGS_INI = "update-settings.ini";
const FILE_UPDATE_SETTINGS_INI_BAK = "update-settings.ini.bak";
const FILE_UPDATE_STATUS = "update.status";
@@ -223,6 +226,7 @@ function setUpdateChannel(aChannel) {
debugDump(
"setting default pref " + PREF_APP_UPDATE_CHANNEL + " to " + gChannel
);
+ gDefaultPrefBranch.unlockPref(PREF_APP_UPDATE_CHANNEL);
gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel);
gPrefRoot.addObserver(PREF_APP_UPDATE_CHANNEL, observer);
}
diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
index 4b12edf6f0..6374f82b52 100644
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -181,6 +181,7 @@ var gDebugTestLog = false;
var gTestsToLog = [];
var gRealDump;
var gFOS;
+var gUpdateBin;
var gTestFiles = [];
var gTestDirs = [];
@@ -189,6 +190,23 @@ var gTestDirs = [];
var gTestFilesCommon = [
{
description: "Should never change",
+ fileName: FILE_CHANNEL_PREFS,
+ relPathDir:
+ AppConstants.platform == "macosx"
+ ? "Contents/Frameworks/ChannelPrefs.framework/"
+ : DIR_RESOURCES + "defaults/pref/",
+ originalContents: "ShouldNotBeReplaced\n",
+ compareContents: "ShouldNotBeReplaced\n",
+ originalFile: null,
+ compareFile: null,
+ originalPerms: 0o767,
+ comparePerms: 0o767,
+ },
+];
+
+var gTestFilesCommonNonMac = [
+ {
+ description: "Should never change",
fileName: FILE_UPDATE_SETTINGS_INI,
relPathDir: DIR_RESOURCES,
originalContents: UPDATE_SETTINGS_CONTENTS,
@@ -198,19 +216,32 @@ var gTestFilesCommon = [
originalPerms: 0o767,
comparePerms: 0o767,
},
+];
+
+if (AppConstants.platform != "macosx") {
+ gTestFilesCommon = gTestFilesCommon.concat(gTestFilesCommonNonMac);
+}
+
+var gTestFilesCommonMac = [
{
description: "Should never change",
- fileName: "channel-prefs.js",
- relPathDir: DIR_RESOURCES + "defaults/pref/",
- originalContents: "ShouldNotBeReplaced\n",
- compareContents: "ShouldNotBeReplaced\n",
+ fileName: FILE_UPDATE_SETTINGS_FRAMEWORK,
+ relPathDir:
+ "Contents/MacOS/updater.app/Contents/Frameworks/UpdateSettings.framework/",
+ originalContents: null,
+ compareContents: null,
originalFile: null,
compareFile: null,
- originalPerms: 0o767,
- comparePerms: 0o767,
+ originalPerms: null,
+ comparePerms: null,
+ existingFile: true,
},
];
+if (AppConstants.platform == "macosx") {
+ gTestFilesCommon = gTestFilesCommon.concat(gTestFilesCommonMac);
+}
+
// Files for a complete successful update. This can be used for a complete
// failed update by calling setTestFilesAndDirsForFailure.
var gTestFilesCompleteSuccess = [
@@ -657,6 +688,20 @@ var gTestFilesPartialSuccess = [
// Concatenate the common files to the end of the array.
gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon);
+/**
+ * Searches `gTestFiles` for the file with the given filename. This is currently
+ * not very efficient (it searches the whole array every time).
+ *
+ * @param filename
+ * The name of the file to search for (i.e. the `fileName` attribute).
+ * @returns
+ * The object in `gTestFiles` that describes the requested file.
+ * Or `null`, if the file is not in `gTestFiles`.
+ */
+function getTestFileByName(filename) {
+ return gTestFiles.find(f => f.fileName == filename) ?? null;
+}
+
var gTestDirsCommon = [
{
relPathDir: DIR_RESOURCES + "3/",
@@ -2019,8 +2064,13 @@ function runUpdate(
Services.env.set("MOZ_TEST_SHORTER_WAIT_PID", "1");
}
- let updateBin = copyTestUpdaterToBinDir();
- Assert.ok(updateBin.exists(), MSG_SHOULD_EXIST + getMsgPath(updateBin.path));
+ if (!gUpdateBin) {
+ gUpdateBin = copyTestUpdaterToBinDir();
+ }
+ Assert.ok(
+ gUpdateBin.exists(),
+ MSG_SHOULD_EXIST + getMsgPath(gUpdateBin.path)
+ );
let updatesDirPath = aPatchDirPath || getUpdateDirFile(DIR_PATCH).path;
let installDirPath = aInstallDirPath || getApplyDirFile().path;
@@ -2045,13 +2095,13 @@ function runUpdate(
args[3] = pid;
}
- let launchBin = gIsServiceTest && isInvalidArgTest ? callbackApp : updateBin;
+ let launchBin = gIsServiceTest && isInvalidArgTest ? callbackApp : gUpdateBin;
if (!isInvalidArgTest) {
args = args.concat([callbackApp.parent.path, callbackApp.path]);
args = args.concat(gCallbackArgs);
} else if (gIsServiceTest) {
- args = ["launch-service", updateBin.path].concat(args);
+ args = ["launch-service", gUpdateBin.path].concat(args);
} else if (aCallbackPath) {
args = args.concat([callbackApp.parent.path, aCallbackPath]);
}
@@ -3125,6 +3175,13 @@ async function setupUpdaterTest(
helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile);
helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile);
+ // On macOS, some test files (like the Update Settings file) may be within the
+ // updater app bundle, so make sure it is in place now in case we want to
+ // manipulate it.
+ if (!gUpdateBin) {
+ gUpdateBin = copyTestUpdaterToBinDir();
+ }
+
gTestFiles.forEach(function SUT_TF_FE(aTestFile) {
debugDump("start - setup test file: " + aTestFile.fileName);
if (aTestFile.originalFile || aTestFile.originalContents) {
@@ -3163,6 +3220,24 @@ async function setupUpdaterTest(
aTestFile.comparePerms = testFile.permissions;
}
}
+ } else if (aTestFile.existingFile) {
+ const testFile = getApplyDirFile(
+ aTestFile.relPathDir + aTestFile.fileName
+ );
+ if (aTestFile.removeOriginalFile) {
+ testFile.remove(false);
+ } else {
+ const fileContents = readFileBytes(testFile);
+ if (!aTestFile.originalContents && !aTestFile.originalFile) {
+ aTestFile.originalContents = fileContents;
+ }
+ if (!aTestFile.compareContents && !aTestFile.compareFile) {
+ aTestFile.compareContents = fileContents;
+ }
+ if (!aTestFile.comparePerms) {
+ aTestFile.comparePerms = testFile.permissions;
+ }
+ }
}
debugDump("finish - setup test file: " + aTestFile.fileName);
});
@@ -3424,21 +3499,13 @@ function checkUpdateLogContents(
// Remove leading timestamps
updateLogContents = removeTimeStamps(updateLogContents);
- // The channel-prefs.js is defined in gTestFilesCommon which will always be
- // located to the end of gTestFiles when it is present.
- if (
- gTestFiles.length > 1 &&
- gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
- !gTestFiles[gTestFiles.length - 1].originalContents
- ) {
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ if (channelPrefs && !channelPrefs.originalContents) {
updateLogContents = updateLogContents.replace(/.*defaults\/.*/g, "");
}
- if (
- gTestFiles.length > 2 &&
- gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
- !gTestFiles[gTestFiles.length - 2].originalContents
- ) {
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI);
+ if (updateSettings && !updateSettings.originalContents) {
updateLogContents = updateLogContents.replace(
/.*update-settings.ini.*/g,
""
@@ -3529,21 +3596,11 @@ function checkUpdateLogContents(
// Remove leading timestamps
compareLogContents = removeTimeStamps(compareLogContents);
- // The channel-prefs.js is defined in gTestFilesCommon which will always be
- // located to the end of gTestFiles.
- if (
- gTestFiles.length > 1 &&
- gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
- !gTestFiles[gTestFiles.length - 1].originalContents
- ) {
+ if (channelPrefs && !channelPrefs.originalContents) {
compareLogContents = compareLogContents.replace(/.*defaults\/.*/g, "");
}
- if (
- gTestFiles.length > 2 &&
- gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
- !gTestFiles[gTestFiles.length - 2].originalContents
- ) {
+ if (updateSettings && !updateSettings.originalContents) {
compareLogContents = compareLogContents.replace(
/.*update-settings.ini.*/g,
""
@@ -4879,3 +4936,33 @@ function resetEnvironment() {
Services.env.set("MOZ_NO_SERVICE_FALLBACK", "");
}
}
+
+/**
+ * `gTestFiles` needs to be set such that it contains the Update Settings file
+ * before this function is called.
+ */
+function setUpdateSettingsUseWrongChannel() {
+ if (AppConstants.platform == "macosx") {
+ let replacementUpdateSettings = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+ replacementUpdateSettings = replacementUpdateSettings.parent;
+ replacementUpdateSettings.append("UpdateSettings-WrongChannel");
+
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_FRAMEWORK);
+ if (!updateSettings) {
+ throw new Error(
+ "gTestFiles does not contain the update settings framework"
+ );
+ }
+ updateSettings.existingFile = false;
+ updateSettings.originalContents = readFileBytes(replacementUpdateSettings);
+ } else {
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI);
+ if (!updateSettings) {
+ throw new Error("gTestFiles does not contain the update settings INI");
+ }
+ updateSettings.originalContents = UPDATE_SETTINGS_CONTENTS.replace(
+ "xpcshell-test",
+ "wrong-channel"
+ );
+ }
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js b/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js
index 9e23fab5e0..1e27efb753 100644
--- a/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js
@@ -177,9 +177,12 @@ add_task(async function testLangpackStaged() {
copyTestUpdaterToBinDir();
let greDir = getGREDir();
- let updateSettingsIni = greDir.clone();
- updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
- writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
+
+ if (AppConstants.platform != "macosx") {
+ let updateSettingsIni = greDir.clone();
+ updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
+ writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
+ }
await downloadUpdate();
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js b/toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js
deleted file mode 100644
index 4cca77c73d..0000000000
--- a/toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-/**
- * This test exists solely to ensure that channel-prefs.js is not changed.
- * If it does get changed, it will cause a variation of Bug 1431342.
- * To summarize, our updater doesn't update that file. But, on macOS, it is
- * still used to compute the application's signature. This means that if Firefox
- * updates and that file has been changed, the signature no will no longer
- * validate.
- */
-
-const expectedChannelPrefsContents = `/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-//
-// This pref is in its own file for complex reasons. See the comment in
-// browser/app/Makefile.in, bug 756325, and bug 1431342 for details. Do not add
-// other prefs to this file.
-
-pref("app.update.channel", "${UpdateUtils.UpdateChannel}");
-`;
-
-async function run_test() {
- let channelPrefsFile = Services.dirsvc.get("GreD", Ci.nsIFile);
- channelPrefsFile.append("defaults");
- channelPrefsFile.append("pref");
- channelPrefsFile.append("channel-prefs.js");
-
- const contents = await IOUtils.readUTF8(channelPrefsFile.path);
- Assert.equal(
- contents,
- expectedChannelPrefsContents,
- "Channel Prefs file should should not change"
- );
-}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml
index 74790016e4..160427ac5e 100644
--- a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml
+++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml
@@ -83,7 +83,3 @@ reason = "Update directory migration is currently Windows only"
["urlConstruction.js"]
skip-if = ["socketprocess_networking"] # Bug 1759035
-
-["verifyChannelPrefsFile.js"]
-run-if = ["appname == 'firefox'"]
-reason = "File being verified is Firefox-specific."
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
index 29c2c2a30e..faac7510d0 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
@@ -10,9 +10,12 @@ async function run_test() {
}
const STATE_AFTER_STAGE = STATE_APPLIED;
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ if (channelPrefs) {
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromComplete\n";
+ channelPrefs.comparePerms = 0o644;
+ }
gTestDirs = gTestDirsCompleteSuccess;
await setupUpdaterTest(FILE_COMPLETE_MAR, true);
setupSymLinks();
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
index de8db067bc..379fb00a27 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
@@ -10,7 +10,7 @@ async function run_test() {
return;
}
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[11].originalFile = "partial.png";
+ getTestFileByName("0exe0.exe").originalFile = "partial.png";
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js
index b93b023934..11181f4420 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js
@@ -15,10 +15,8 @@ async function run_test() {
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperFileInUse(
- gTestFiles[13].relPathDir + gTestFiles[13].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
checkFilesAfterUpdateSuccess(getStageDirFile, true);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js
index b41da12396..def7f8db9c 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js
@@ -15,10 +15,8 @@ async function run_test() {
gTestFiles = gTestFilesPartialSuccess;
gTestDirs = gTestDirsPartialSuccess;
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperFileInUse(
- gTestFiles[11].relPathDir + gTestFiles[11].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
checkFilesAfterUpdateSuccess(getStageDirFile, true);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
index 4b946ac3e4..d1f938bb02 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
@@ -11,10 +11,8 @@ async function run_test() {
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperFileInUse(
- gTestFiles[13].relPathDir + gTestFiles[13].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
runUpdate(STATE_SUCCEEDED, false, 0, true);
await waitForHelperExit();
await checkPostUpdateAppLog();
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
index 15c3a1121a..f851c543a6 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
@@ -11,10 +11,8 @@ async function run_test() {
gTestFiles = gTestFilesPartialSuccess;
gTestDirs = gTestDirsPartialSuccess;
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperFileInUse(
- gTestFiles[11].relPathDir + gTestFiles[11].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
runUpdate(STATE_SUCCEEDED, false, 0, true);
await waitForHelperExit();
await checkPostUpdateAppLog();
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
index 698ccb7fe5..5517d5ed81 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
@@ -12,7 +12,7 @@ async function run_test() {
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperLockFile(gTestFiles[3]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng0.png"));
runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, true);
await waitForHelperExit();
standardInit();
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
index c8c019ec5c..03eb6122c8 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
@@ -12,7 +12,7 @@ async function run_test() {
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperLockFile(gTestFiles[2]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng1.png"));
runUpdate(STATE_FAILED_READ_ERROR, false, 1, true);
await waitForHelperExit();
standardInit();
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
index 7b582dbd45..4d5fe599cf 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
@@ -13,7 +13,7 @@ async function run_test() {
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperLockFile(gTestFiles[3]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng0.png"));
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
// Files aren't checked after staging since this test locks a file which
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
index bf3abd8c37..3d4a8e0c51 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
@@ -13,7 +13,7 @@ async function run_test() {
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperLockFile(gTestFiles[2]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng1.png"));
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
// Files aren't checked after staging since this test locks a file which
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js
index b0a0cfe657..fbb0e7c4cd 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js
@@ -14,7 +14,17 @@ async function run_test() {
return;
}
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 2].originalContents = null;
+ if (AppConstants.platform == "macosx") {
+ // On macOS, the update settings Framework already exists. Remove it.
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_FRAMEWORK);
+ updateSettings.removeOriginalFile = true;
+ } else {
+ // On non-macOS, the update settings INI will normally be written out with
+ // the contents specified by `originalContents`. Setting this to `null`
+ // prevents anything from being written out.
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI);
+ updateSettings.originalContents = null;
+ }
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js
index e26d2aefc3..a6d204aa92 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js
@@ -15,7 +15,17 @@ async function run_test() {
}
const STATE_AFTER_STAGE = STATE_FAILED;
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 2].originalContents = null;
+ if (AppConstants.platform == "macosx") {
+ // On macOS, the update settings Framework already exists. Remove it.
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_FRAMEWORK);
+ updateSettings.removeOriginalFile = true;
+ } else {
+ // On non-macOS, the update settings INI will normally be written out with
+ // the contents specified by `originalContents`. Setting this to `null`
+ // prevents anything from being written out.
+ const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI);
+ updateSettings.originalContents = null;
+ }
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
index a1a0de0fe4..47c184e67b 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
@@ -11,7 +11,7 @@ async function run_test() {
}
const STATE_AFTER_STAGE = STATE_FAILED;
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[11].originalFile = "partial.png";
+ getTestFileByName("0exe0.exe").originalFile = "partial.png";
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
index 943a45ba95..2c9c3298d4 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
@@ -11,9 +11,10 @@ async function run_test() {
}
const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED;
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromComplete\n";
+ channelPrefs.comparePerms = 0o644;
gTestDirs = gTestDirsCompleteSuccess;
setupSymLinks();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
index dd5c240919..e565ffe550 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
@@ -11,9 +11,10 @@ async function run_test() {
}
const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED;
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromPartial\n";
+ channelPrefs.comparePerms = 0o644;
gTestDirs = gTestDirsPartialSuccess;
preventDistributionFiles();
await setupUpdaterTest(FILE_PARTIAL_MAR, true);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
index 8e8e9d094a..f4f856278c 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
@@ -10,9 +10,10 @@ async function run_test() {
return;
}
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromPartial\n";
+ channelPrefs.comparePerms = 0o644;
gTestDirs = gTestDirsPartialSuccess;
// The third parameter will test that a relative path that contains a
// directory traversal to the post update binary doesn't execute.
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js
index 37511bd789..e80e52e9a3 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js
@@ -45,8 +45,7 @@ async function run_test() {
// won't be updated if it already exists. The manipulations below arrange a)
// for the file to exist and b) for the comparison afterward to succeed.
gTestFiles = gTestFilesPartialSuccess;
- let channelPrefs = gTestFiles[gTestFiles.length - 1];
- Assert.equal("channel-prefs.js", channelPrefs.fileName);
+ let channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
let f = gGREDirOrig.clone();
f.append("defaults");
f.append("pref");
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
index d31188dcca..5d6ee61776 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
@@ -14,8 +14,7 @@ async function run_test() {
return;
}
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 2].originalContents =
- UPDATE_SETTINGS_CONTENTS.replace("xpcshell-test", "wrong-channel");
+ setUpdateSettingsUseWrongChannel();
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js
index 4d512fd12a..9aca22df66 100644
--- a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js
@@ -15,8 +15,7 @@ async function run_test() {
}
const STATE_AFTER_STAGE = STATE_FAILED;
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 2].originalContents =
- UPDATE_SETTINGS_CONTENTS.replace("xpcshell-test", "wrong-channel");
+ setUpdateSettingsUseWrongChannel();
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js
index de8db067bc..379fb00a27 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js
@@ -10,7 +10,7 @@ async function run_test() {
return;
}
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[11].originalFile = "partial.png";
+ getTestFileByName("0exe0.exe").originalFile = "partial.png";
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js
index b93b023934..11181f4420 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js
@@ -15,10 +15,8 @@ async function run_test() {
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperFileInUse(
- gTestFiles[13].relPathDir + gTestFiles[13].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
checkFilesAfterUpdateSuccess(getStageDirFile, true);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js
index b41da12396..def7f8db9c 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js
@@ -15,10 +15,8 @@ async function run_test() {
gTestFiles = gTestFilesPartialSuccess;
gTestDirs = gTestDirsPartialSuccess;
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperFileInUse(
- gTestFiles[11].relPathDir + gTestFiles[11].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
checkFilesAfterUpdateSuccess(getStageDirFile, true);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js
index 4b946ac3e4..d1f938bb02 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js
@@ -11,10 +11,8 @@ async function run_test() {
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperFileInUse(
- gTestFiles[13].relPathDir + gTestFiles[13].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
runUpdate(STATE_SUCCEEDED, false, 0, true);
await waitForHelperExit();
await checkPostUpdateAppLog();
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js
index 15c3a1121a..f851c543a6 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js
@@ -11,10 +11,8 @@ async function run_test() {
gTestFiles = gTestFilesPartialSuccess;
gTestDirs = gTestDirsPartialSuccess;
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperFileInUse(
- gTestFiles[11].relPathDir + gTestFiles[11].fileName,
- false
- );
+ const testFile = getTestFileByName("0exe0.exe");
+ await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false);
runUpdate(STATE_SUCCEEDED, false, 0, true);
await waitForHelperExit();
await checkPostUpdateAppLog();
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js
index 698ccb7fe5..5517d5ed81 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js
@@ -12,7 +12,7 @@ async function run_test() {
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperLockFile(gTestFiles[3]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng0.png"));
runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, true);
await waitForHelperExit();
standardInit();
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js
index c8c019ec5c..03eb6122c8 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js
@@ -12,7 +12,7 @@ async function run_test() {
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperLockFile(gTestFiles[2]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng1.png"));
runUpdate(STATE_FAILED_READ_ERROR, false, 1, true);
await waitForHelperExit();
standardInit();
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js
index 7b582dbd45..4d5fe599cf 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js
@@ -13,7 +13,7 @@ async function run_test() {
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
- await runHelperLockFile(gTestFiles[3]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng0.png"));
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
// Files aren't checked after staging since this test locks a file which
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js
index bf3abd8c37..3d4a8e0c51 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js
@@ -13,7 +13,7 @@ async function run_test() {
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
- await runHelperLockFile(gTestFiles[2]);
+ await runHelperLockFile(getTestFileByName("searchpluginspng1.png"));
await stageUpdate(STATE_AFTER_STAGE, true);
checkPostUpdateRunningFile(false);
// Files aren't checked after staging since this test locks a file which
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js
index a1a0de0fe4..47c184e67b 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js
@@ -11,7 +11,7 @@ async function run_test() {
}
const STATE_AFTER_STAGE = STATE_FAILED;
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[11].originalFile = "partial.png";
+ getTestFileByName("0exe0.exe").originalFile = "partial.png";
gTestDirs = gTestDirsPartialSuccess;
setTestFilesAndDirsForFailure();
await setupUpdaterTest(FILE_PARTIAL_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js
index 943a45ba95..2c9c3298d4 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js
@@ -11,9 +11,10 @@ async function run_test() {
}
const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED;
gTestFiles = gTestFilesCompleteSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromComplete\n";
+ channelPrefs.comparePerms = 0o644;
gTestDirs = gTestDirsCompleteSuccess;
setupSymLinks();
await setupUpdaterTest(FILE_COMPLETE_MAR, false);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js
index dd5c240919..e565ffe550 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js
@@ -11,9 +11,10 @@ async function run_test() {
}
const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED;
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromPartial\n";
+ channelPrefs.comparePerms = 0o644;
gTestDirs = gTestDirsPartialSuccess;
preventDistributionFiles();
await setupUpdaterTest(FILE_PARTIAL_MAR, true);
diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js
index 8e8e9d094a..f4f856278c 100644
--- a/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js
@@ -10,9 +10,10 @@ async function run_test() {
return;
}
gTestFiles = gTestFilesPartialSuccess;
- gTestFiles[gTestFiles.length - 1].originalContents = null;
- gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n";
- gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
+ const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS);
+ channelPrefs.originalContents = null;
+ channelPrefs.compareContents = "FromPartial\n";
+ channelPrefs.comparePerms = 0o644;
gTestDirs = gTestDirsPartialSuccess;
// The third parameter will test that a relative path that contains a
// directory traversal to the post update binary doesn't execute.
diff --git a/toolkit/mozapps/update/updater/Makefile.in b/toolkit/mozapps/update/updater/Makefile.in
index 70cf32378a..ec3ad9773a 100644
--- a/toolkit/mozapps/update/updater/Makefile.in
+++ b/toolkit/mozapps/update/updater/Makefile.in
@@ -25,4 +25,7 @@ libs::
$(call py_action,preprocessor updater.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings)
$(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS
$(NSINSTALL) $(DIST)/bin/org.mozilla.updater $(DIST)/bin/updater.app/Contents/MacOS
+ $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/Frameworks
+ $(NSINSTALL) $(DIST)/bin/UpdateSettings $(DIST)/bin/updater.app/Contents/Frameworks/UpdateSettings.framework
+ $(NSINSTALL) $(srcdir)/macos-frameworks/UpdateSettings/Info.plist $(DIST)/bin/updater.app/Contents/Frameworks/UpdateSettings.framework/Resources
endif
diff --git a/toolkit/mozapps/update/updater/launchchild_osx.mm b/toolkit/mozapps/update/updater/launchchild_osx.mm
index 917f282d9f..b64e85980c 100644
--- a/toolkit/mozapps/update/updater/launchchild_osx.mm
+++ b/toolkit/mozapps/update/updater/launchchild_osx.mm
@@ -280,8 +280,9 @@ void CleanupElevatedMacUpdate(bool aFailureOccurred) {
LaunchChild(3, launchctlArgs);
}
-// Note: Caller is responsible for freeing argv.
-bool ObtainUpdaterArguments(int* argc, char*** argv) {
+// Note: Caller is responsible for freeing aArgv.
+bool ObtainUpdaterArguments(int* aArgc, char*** aArgv,
+ MARChannelStringTable* aMARStrings) {
MacAutoreleasePool pool;
id updateServer = ConnectToUpdateServer();
@@ -294,15 +295,22 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
@try {
NSArray* updaterArguments =
[updateServer performSelector:@selector(getArguments)];
- *argc = [updaterArguments count];
- char** tempArgv = (char**)malloc(sizeof(char*) * (*argc));
- for (int i = 0; i < *argc; i++) {
+ *aArgc = [updaterArguments count];
+ char** tempArgv = (char**)malloc(sizeof(char*) * (*aArgc));
+ for (int i = 0; i < *aArgc; i++) {
int argLen = [[updaterArguments objectAtIndex:i] length] + 1;
tempArgv[i] = (char*)malloc(argLen);
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String],
argLen);
}
- *argv = tempArgv;
+ *aArgv = tempArgv;
+
+ NSString* channelID =
+ [updateServer performSelector:@selector(getMARChannelID)];
+ const char* channelIDStr = [channelID UTF8String];
+ aMARStrings->MARChannelID =
+ mozilla::MakeUnique<char[]>(strlen(channelIDStr) + 1);
+ strcpy(aMARStrings->MARChannelID.get(), channelIDStr);
} @catch (NSException* e) {
// Let's try our best and clean up.
CleanupElevatedMacUpdate(true);
@@ -321,10 +329,12 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
NSArray* mUpdaterArguments;
BOOL mShouldKeepRunning;
BOOL mAborted;
+ NSString* mMARChannelID;
}
-- (id)initWithArgs:(NSArray*)args;
+- (id)initWithArgs:(NSArray*)aArgs marChannelID:(NSString*)aMARChannelID;
- (BOOL)runServer;
- (NSArray*)getArguments;
+- (NSString*)getMARChannelID;
- (void)abort;
- (BOOL)wasAborted;
- (void)shutdown;
@@ -333,12 +343,13 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
@implementation ElevatedUpdateServer
-- (id)initWithArgs:(NSArray*)args {
+- (id)initWithArgs:(NSArray*)aArgs marChannelID:(NSString*)aMARChannelID {
self = [super init];
if (!self) {
return nil;
}
- mUpdaterArguments = args;
+ mUpdaterArguments = aArgs;
+ mMARChannelID = aMARChannelID;
mShouldKeepRunning = YES;
mAborted = NO;
return self;
@@ -367,6 +378,20 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
return mUpdaterArguments;
}
+/**
+ * The MAR channel ID(s) are stored in the UpdateSettings.framework that ships
+ * with the updater.app bundle. When an elevated update is occurring, the
+ * org.mozilla.updater binary is extracted and installed individually as a
+ * Privileged Helper Tool. This Privileged Helper Tool does not have access to
+ * the UpdateSettings.framework and we therefore rely on the unelevated updater
+ * process to pass this information to the elevated updater process in the same
+ * fashion that the command line arguments are passed to the elevated updater
+ * process by `getArguments`.
+ */
+- (NSString*)getMARChannelID {
+ return mMARChannelID;
+}
+
- (void)abort {
mAborted = YES;
[self shutdown];
@@ -386,16 +411,19 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
@end
-bool ServeElevatedUpdate(int argc, const char** argv) {
+bool ServeElevatedUpdate(int aArgc, const char** aArgv,
+ const char* aMARChannelID) {
MacAutoreleasePool pool;
- NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:argc];
- for (int i = 0; i < argc; i++) {
- [updaterArguments addObject:[NSString stringWithUTF8String:argv[i]]];
+ NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:aArgc];
+ for (int i = 0; i < aArgc; i++) {
+ [updaterArguments addObject:[NSString stringWithUTF8String:aArgv[i]]];
}
+ NSString* channelID = [NSString stringWithUTF8String:aMARChannelID];
ElevatedUpdateServer* updater =
- [[ElevatedUpdateServer alloc] initWithArgs:[updaterArguments copy]];
+ [[ElevatedUpdateServer alloc] initWithArgs:updaterArguments
+ marChannelID:channelID];
bool didSucceed = [updater runServer];
[updater release];
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build
new file mode 100644
index 0000000000..e1f4ad0981
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Framework("UpdateSettings-WrongChannel")
+FINAL_TARGET = "_tests/xpcshell/toolkit/mozapps/update/tests"
+
+DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"wrong-channel"'
+
+UNIFIED_SOURCES += [
+ "../UpdateSettings/UpdateSettings.mm",
+]
+
+OS_LIBS += [
+ "-framework Foundation",
+]
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build
new file mode 100644
index 0000000000..6c9b43b146
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Framework("UpdateSettings-xpcshell")
+FINAL_TARGET = "_tests/xpcshell/toolkit/mozapps/update/tests"
+
+DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"xpcshell-test"'
+
+UNIFIED_SOURCES += [
+ "../UpdateSettings/UpdateSettings.mm",
+]
+
+OS_LIBS += [
+ "-framework Foundation",
+]
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist
new file mode 100644
index 0000000000..65777a475f
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>UpdateSettings</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.mozilla.updatesettings</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>UpdateSettings</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md
new file mode 100644
index 0000000000..32b9d2ea48
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md
@@ -0,0 +1,77 @@
+# UpdateSettings macOS Framework
+
+## Summary
+
+The UpdateSettings macOS Framework is used to set the accepted MAR download
+channels.
+
+## What are MAR update channels and what are they used for?
+
+As the name implies, MAR update channels are the channels where MAR update files
+are served from and we want to ensure that the updater only applies MAR files
+from accepted channels.
+
+## Why do we need a Framework instead of compiling the accepted MAR update channels directly into the executable?
+
+There are three main use cases that make it necessary for the accepted MAR
+update channels to be set by external means, such as a macOS Framework:
+
+ 1. Allowing users on the Beta channel to test RC builds
+
+Our beta users test release candidate builds before they are released to the
+release population. The MAR files related to release candidates have their MAR
+channel set to `release`. We make it possible for beta users to test these
+release candidate MAR files by having beta Firefox installs accept MAR files
+with their internal update channel set to either `release` or `beta`.
+
+ 2. Switching users to another channel, such as ESR
+
+In contrast to the Beta use case outlined above, there are times where we
+explicitly WANT to switch users to a different channel. An example of this is
+when hardware or a particular macOS version have reached their EOL. In this
+case, we usually switch users to our ESR channel for extended support. We switch
+users to a different channel by serving a MAR file that forces a change to the
+update channels that will be accepted for future updates. In other words, while
+users may have previously accepted MAR update files from the `release` channel,
+they now only accept MAR files from the `esr` channel.
+
+ 3. QA update testing
+
+QA requires a way to temporarily switch the MAR update channel to a test channel
+in order to test MAR updates before new releases.
+
+## How does the UpdateSettings macOS Framework address these use cases?
+
+We are able to accommodate all three use cases above by enabling the updater to
+ignore certain files on disk if they are already present, but continue to force
+update them if so desired.
+
+In the case of a Beta user updating to an RC build, the updater would encounter
+an UpdateSettings macOS Framework inside the .app bundle that has the accepted
+MAR update channels set to `beta` and `release`. In this case, the updater will
+not update the Framework, but update everything else. This beta user is now able
+to run the RC build with the update channel still set to `beta` and `release`
+and will be able to apply MAR files related to the next beta cycle once the end
+of RC builds is reached.
+
+In the case of switching users to the ESR channel, the updater will be set to
+forcefully update the UpdateSettings macOS Framework, even if already present on
+disk. After the update, the user will now be set to accept MAR updates from the
+`esr` channel only.
+
+Before releases, QA replaces the UpdateSettings macOS Framework within the .app
+bundle and set the accepted MAR update channels to a test channel in order to
+test MAR updates. During testing, the new Framework file would remain in place
+for typical update testing, but gets replaced in case QA was testing channel
+switching.
+
+## Why is a macOS Framework the best solution to store the accepted MAR update channels?
+
+Apple has started strengthening code signature checks and the requirements on
+developers such as ourselves on how their apps are signed. In particular,
+most files in the .app bundle are now included in signature verifications.
+
+A macOS Framework is the ideal solution to store the accepted MAR update
+channels because Frameworks are the only component within a .app bundle that can
+be replaced without invalidating the code signature on the .app bundle, as long
+as both the previous and the new Framework are signed.
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h
new file mode 100644
index 0000000000..65a7ba3e00
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UpdateSettings_h_
+#define UpdateSettings_h_
+
+#import <Foundation/Foundation.h>
+
+extern "C" {
+
+// Returns the accepted MAR channels, as an autoreleased string.
+extern NSString* UpdateSettingsGetAcceptedMARChannels(void)
+ __attribute__((weak_import)) __attribute__((visibility("default")));
+}
+
+#endif // UpdateSettings_h_
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm
new file mode 100644
index 0000000000..2c39f13f3b
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm
@@ -0,0 +1,13 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "UpdateSettings.h"
+
+#include "mozilla/HelperMacros.h"
+
+NSString* UpdateSettingsGetAcceptedMARChannels(void) {
+ return
+ [NSString stringWithFormat:@"[Settings]\nACCEPTED_MAR_CHANNEL_IDS=%s\n",
+ ACCEPTED_MAR_CHANNEL_IDS];
+}
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build
new file mode 100644
index 0000000000..67de1d68f7
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Framework("UpdateSettings")
+
+if CONFIG["ACCEPTED_MAR_CHANNEL_IDS"]:
+ DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"%s"' % CONFIG["ACCEPTED_MAR_CHANNEL_IDS"]
+else:
+ DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '""'
+
+EXPORTS += [
+ "UpdateSettings.h",
+]
+
+UNIFIED_SOURCES += [
+ "UpdateSettings.mm",
+]
+
+OS_LIBS += [
+ "-framework Foundation",
+]
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h
new file mode 100644
index 0000000000..5964d9fb18
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UpdateSettingsUtil_h_
+#define UpdateSettingsUtil_h_
+
+#include <optional>
+#include <string>
+
+class UpdateSettingsUtil {
+ public:
+ static std::optional<std::string> GetAcceptedMARChannelsValue();
+};
+
+#endif // UpdateSettingsUtil_h_
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm
new file mode 100644
index 0000000000..6555fd1350
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm
@@ -0,0 +1,21 @@
+/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset:
+ * 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#import "UpdateSettings/UpdateSettings.h"
+
+#include "UpdateSettingsUtil.h"
+
+/* static */
+std::optional<std::string> UpdateSettingsUtil::GetAcceptedMARChannelsValue() {
+ // `UpdateSettingsGetAcceptedMARChannels` is resolved at runtime and requires
+ // the UpdateSettings framework to be loaded.
+ if (UpdateSettingsGetAcceptedMARChannels) {
+ NSString* marChannels = UpdateSettingsGetAcceptedMARChannels();
+ return [marChannels UTF8String];
+ }
+ return {};
+}
diff --git a/toolkit/mozapps/update/updater/macos-frameworks/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/moz.build
new file mode 100644
index 0000000000..19fa11942e
--- /dev/null
+++ b/toolkit/mozapps/update/updater/macos-frameworks/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+with Files("**"):
+ BUG_COMPONENT = ("Toolkit", "Application Update")
+
+DIRS += ["UpdateSettings", "UpdateSettings-xpcshell", "UpdateSettings-WrongChannel"]
+
+EXPORTS += [
+ "UpdateSettingsUtil.h",
+]
+
+UNIFIED_SOURCES += [
+ "UpdateSettingsUtil.mm",
+]
diff --git a/toolkit/mozapps/update/updater/moz.build b/toolkit/mozapps/update/updater/moz.build
index eede9cd723..9620dde22c 100644
--- a/toolkit/mozapps/update/updater/moz.build
+++ b/toolkit/mozapps/update/updater/moz.build
@@ -26,6 +26,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
"__launchd_plist",
SRCDIR + "/Launchd.plist",
]
+ DIRS += [
+ "macos-frameworks",
+ ]
GENERATED_FILES = [
"dep1Cert.h",
diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build
index fe0b4a85fa..6c6d0adf6f 100644
--- a/toolkit/mozapps/update/updater/updater-common.build
+++ b/toolkit/mozapps/update/updater/updater-common.build
@@ -22,6 +22,17 @@ if CONFIG["MOZ_VERIFY_MAR_SIGNATURE"]:
"verifymar",
]
+ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
+ srcs += [
+ "macos-frameworks/UpdateSettingsUtil.mm",
+ ]
+ USE_LIBS += [
+ "UpdateSettings",
+ ]
+ LDFLAGS += [
+ "-Wl,-rpath,@executable_path/../Frameworks/UpdateSettings.framework"
+ ]
+
if CONFIG["OS_ARCH"] == "WINNT":
have_progressui = 1
srcs += [
@@ -114,7 +125,7 @@ if CONFIG["MOZ_TSAN"]:
DEFINES["SPRINTF_H_USES_VSNPRINTF"] = True
DEFINES["NS_NO_XPCOM"] = True
DisableStlWrapping()
-for var in ("MAR_CHANNEL_ID", "MOZ_APP_VERSION"):
+for var in ("MAR_CHANNEL_ID", "MOZ_APP_VERSION", "ACCEPTED_MAR_CHANNEL_IDS"):
DEFINES[var] = '"%s"' % CONFIG[var]
LOCAL_INCLUDES += [
diff --git a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
index 533533c4d9..7ef90f9ce5 100644
--- a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
+++ b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
@@ -30,6 +30,10 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
$(call py_action,preprocessor updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings)
$(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/MacOS
$(NSINSTALL) $(FINAL_TARGET)/updater-xpcshell $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/MacOS
+ $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks
+ $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework
+ cp $(XPCSHELLTESTDIR)/UpdateSettings-xpcshell $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework/UpdateSettings
+ $(NSINSTALL) $(srcdir)/../macos-frameworks/UpdateSettings/Info.plist $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework/Resources
rm -Rf $(XPCSHELLTESTDIR)/data/updater.app
mv $(XPCSHELLTESTDIR)/data/updater-xpcshell.app $(XPCSHELLTESTDIR)/data/updater.app
mv $(XPCSHELLTESTDIR)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTDIR)/data/updater.app/Contents/MacOS/org.mozilla.updater
diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp
index 6b01450b31..084945dc44 100644
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -46,6 +46,7 @@
#include "updatecommon.h"
#ifdef XP_MACOSX
+# include "UpdateSettingsUtil.h"
# include "updaterfileutils_osx.h"
#endif // XP_MACOSX
@@ -75,13 +76,16 @@ bool IsOwnedByGroupAdmin(const char* aAppBundle);
bool IsRecursivelyWritable(const char* aPath);
void LaunchChild(int argc, const char** argv);
void LaunchMacPostProcess(const char* aAppBundle);
-bool ObtainUpdaterArguments(int* argc, char*** argv);
-bool ServeElevatedUpdate(int argc, const char** argv);
+bool ObtainUpdaterArguments(int* aArgc, char*** aArgv,
+ MARChannelStringTable* aMARStrings);
+bool ServeElevatedUpdate(int aArgc, const char** aArgv,
+ const char* aMARChannelID);
void SetGroupOwnershipAndPermissions(const char* aAppBundle);
bool PerformInstallationFromDMG(int argc, char** argv);
struct UpdateServerThreadArgs {
int argc;
const NS_tchar** argv;
+ const char* marChannelID;
};
#endif
@@ -187,15 +191,6 @@ class AutoFile {
}
};
-struct MARChannelStringTable {
- MARChannelStringTable() {
- MARChannelID = mozilla::MakeUnique<char[]>(1);
- MARChannelID[0] = '\0';
- }
-
- mozilla::UniquePtr<char[]> MARChannelID;
-};
-
//-----------------------------------------------------------------------------
#ifdef XP_MACOSX
@@ -292,6 +287,10 @@ static bool sUsingService = false;
// that iteration will run with `gIsElevated == true`.
static bool gIsElevated = false;
+// This string contains the MAR channel IDs that are later extracted by one of
+// the `ReadMARChannelIDsFrom` variants.
+static MARChannelStringTable gMARStrings;
+
// Normally, we run updates as a result of user action (the user started Firefox
// or clicked a "Restart to Update" button). But there are some cases when
// we are not:
@@ -2659,23 +2658,67 @@ static void WaitForServiceFinishThread(void* param) {
#endif
#ifdef MOZ_VERIFY_MAR_SIGNATURE
+# ifndef XP_MACOSX
/**
* This function reads in the ACCEPTED_MAR_CHANNEL_IDS from update-settings.ini
*
- * @param path The path to the ini file that is to be read
- * @param results A pointer to the location to store the read strings
+ * @param aPath The path to the ini file that is to be read
+ * @param aResults A pointer to the location to store the read strings
+ * @return OK on success
+ */
+static int ReadMARChannelIDsFromPath(const NS_tchar* aPath,
+ MARChannelStringTable* aResults) {
+ const unsigned int kNumStrings = 1;
+ const char* kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0";
+ return ReadStrings(aPath, kUpdaterKeys, kNumStrings, &aResults->MARChannelID,
+ "Settings");
+}
+# else // XP_MACOSX
+/**
+ * This function reads in the ACCEPTED_MAR_CHANNEL_IDS from a string buffer.
+ *
+ * @param aChannels A string buffer containing the MAR channel(s).
+ * @param aResults A pointer to the location to store the read strings.
* @return OK on success
*/
-static int ReadMARChannelIDs(const NS_tchar* path,
- MARChannelStringTable* results) {
+static int ReadMARChannelIDsFromBuffer(char* aChannels,
+ MARChannelStringTable* aResults) {
const unsigned int kNumStrings = 1;
const char* kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0";
- int result = ReadStrings(path, kUpdaterKeys, kNumStrings,
- &results->MARChannelID, "Settings");
+ return ReadStringsFromBuffer(aChannels, kUpdaterKeys, kNumStrings,
+ &aResults->MARChannelID, "Settings");
+}
+# endif // XP_MACOSX
- return result;
+/**
+ * This function reads in the `ACCEPTED_MAR_CHANNEL_IDS` from the appropriate
+ * (platform-dependent) source and populates `gMARStrings`.
+ *
+ * @return
+ * `OK` on success, `UPDATE_SETTINGS_FILE_CHANNEL` on failure.
+ */
+static int PopulategMARStrings() {
+ int rv = UPDATE_SETTINGS_FILE_CHANNEL;
+# ifdef XP_MACOSX
+ if (gIsElevated) {
+ // An elevated update process will have already populated gMARStrings when
+ // it connected to the unelevated update process to obtain the command line
+ // args. See `ObtainUpdaterArguments`.
+ rv = OK;
+ } else if (auto marChannels =
+ UpdateSettingsUtil::GetAcceptedMARChannelsValue()) {
+ rv = ReadMARChannelIDsFromBuffer(marChannels->data(), &gMARStrings);
+ }
+# else
+ NS_tchar updateSettingsPath[MAXPATHLEN];
+ NS_tsnprintf(updateSettingsPath,
+ sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
+ NS_T("%s/update-settings.ini"), gInstallDirPath);
+ rv = ReadMARChannelIDsFromPath(updateSettingsPath, &gMARStrings);
+# endif
+ return rv == OK ? OK : UPDATE_SETTINGS_FILE_CHANNEL;
}
-#endif
+#endif // MOZ_VERIFY_MAR_SIGNATURE
static int GetUpdateFileName(NS_tchar* fileName, int maxChars) {
NS_tsnprintf(fileName, maxChars, NS_T("%s/update.mar"), gPatchDirPath);
@@ -2700,21 +2743,10 @@ static void UpdateThreadFunc(void* param) {
}
if (rv == OK) {
- NS_tchar updateSettingsPath[MAXPATHLEN];
- NS_tsnprintf(updateSettingsPath,
- sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
-# ifdef XP_MACOSX
- NS_T("%s/Contents/Resources/update-settings.ini"),
-# else
- NS_T("%s/update-settings.ini"),
-# endif
- gInstallDirPath);
- MARChannelStringTable MARStrings;
- if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
- rv = UPDATE_SETTINGS_FILE_CHANNEL;
- } else {
+ rv = PopulategMARStrings();
+ if (rv == OK) {
rv = gArchiveReader.VerifyProductInformation(
- MARStrings.MARChannelID.get(), MOZ_APP_VERSION);
+ gMARStrings.MARChannelID.get(), MOZ_APP_VERSION);
}
}
#endif
@@ -2819,7 +2851,8 @@ static void UpdateThreadFunc(void* param) {
#ifdef XP_MACOSX
static void ServeElevatedUpdateThreadFunc(void* param) {
UpdateServerThreadArgs* threadArgs = (UpdateServerThreadArgs*)param;
- gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv);
+ gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv,
+ threadArgs->marChannelID);
if (!gSucceeded) {
WriteStatusFile(ELEVATION_CANCELED);
}
@@ -2955,6 +2988,21 @@ int NS_main(int argc, NS_tchar** argv) {
putenv(const_cast<char*>("MOZ_USING_SERVICE="));
#endif
+ if (argc == 2 && NS_tstrcmp(argv[1], NS_T("--channels-allowed")) == 0) {
+#ifdef MOZ_VERIFY_MAR_SIGNATURE
+ int rv = PopulategMARStrings();
+ if (rv == OK) {
+ printf("Channels Allowed: %s\n", gMARStrings.MARChannelID.get());
+ return 0;
+ }
+ printf("Error: %d\n", rv);
+ return 1;
+#else
+ printf("Not Applicable: No support for signature verification\n");
+ return 0;
+#endif
+ }
+
// The callback is the remaining arguments starting at callbackIndex.
// The argument specified by callbackIndex is the callback executable and the
// argument prior to callbackIndex is the working directory.
@@ -2977,7 +3025,7 @@ int NS_main(int argc, NS_tchar** argv) {
strstr(argv[0], "/Library/PrivilegedHelperTools/org.mozilla.updater") !=
0;
if (isElevated) {
- if (!ObtainUpdaterArguments(&argc, &argv)) {
+ if (!ObtainUpdaterArguments(&argc, &argv, &gMARStrings)) {
// Won't actually get here because ObtainUpdaterArguments will terminate
// the current process on failure.
return 1;
@@ -3288,6 +3336,7 @@ int NS_main(int argc, NS_tchar** argv) {
UpdateServerThreadArgs threadArgs;
threadArgs.argc = argc;
threadArgs.argv = const_cast<const NS_tchar**>(argv);
+ threadArgs.marChannelID = gMARStrings.MARChannelID.get();
Thread t1;
if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) {
@@ -4179,7 +4228,7 @@ int NS_main(int argc, NS_tchar** argv) {
// Run update process on a background thread. ShowProgressUI may return
// before QuitProgressUI has been called, so wait for UpdateThreadFunc to
// terminate. Avoid showing the progress UI when staging an update, or if
- // this is an elevated process on OSX.
+ // this is an elevated process on macOS.
Thread t;
if (t.Run(UpdateThreadFunc, nullptr) == 0) {
if (!sStagedUpdate && !sReplaceRequest && !sUpdateSilently