Issue #65 - Remove AppConstants from toolkit/mozapps/update

This commit is contained in:
Matt A. Tobin 2020-02-05 14:31:58 -05:00 • committed by Roy Tam
commit f77d815b53
2 changed files with 152 additions and 143 deletions

View file

@ -18,11 +18,12 @@ XPIDL_SOURCES += [
TEST_DIRS += ['tests'] TEST_DIRS += ['tests']
EXTRA_COMPONENTS += [ EXTRA_COMPONENTS += [
'nsUpdateService.js',
'nsUpdateService.manifest', 'nsUpdateService.manifest',
'nsUpdateServiceStub.js', 'nsUpdateServiceStub.js',
] ]
EXTRA_PP_COMPONENTS += ['nsUpdateService.js']
JAR_MANIFESTS += ['jar.mn'] JAR_MANIFESTS += ['jar.mn']
with Files('**'): with Files('**'):

View file

@ -12,7 +12,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
Cu.import("resource://gre/modules/FileUtils.jsm", this); Cu.import("resource://gre/modules/FileUtils.jsm", this);
Cu.import("resource://gre/modules/Services.jsm", this); Cu.import("resource://gre/modules/Services.jsm", this);
Cu.import("resource://gre/modules/ctypes.jsm", this); Cu.import("resource://gre/modules/ctypes.jsm", this);
Cu.import("resource://gre/modules/AppConstants.jsm", this);
Cu.importGlobalProperties(["XMLHttpRequest"]); Cu.importGlobalProperties(["XMLHttpRequest"]);
const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"); const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}");
@ -219,10 +218,7 @@ function closeHandle(handle) {
* @return The Win32 handle to the mutex. * @return The Win32 handle to the mutex.
*/ */
function createMutex(aName, aAllowExisting = true) { function createMutex(aName, aAllowExisting = true) {
if (AppConstants.platform != "win") { #ifdef XP_WIN
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
}
const INITIAL_OWN = 1; const INITIAL_OWN = 1;
const ERROR_ALREADY_EXISTS = 0xB7; const ERROR_ALREADY_EXISTS = 0xB7;
let lib = ctypes.open("kernel32.dll"); let lib = ctypes.open("kernel32.dll");
@ -246,6 +242,9 @@ function createMutex(aName, aAllowExisting = true) {
} }
return handle; return handle;
#else
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
#endif
} }
/** /**
@ -257,10 +256,7 @@ function createMutex(aName, aAllowExisting = true) {
* @return Global mutex path * @return Global mutex path
*/ */
function getPerInstallationMutexName(aGlobal = true) { function getPerInstallationMutexName(aGlobal = true) {
if (AppConstants.platform != "win") { #ifdef XP_WIN
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
}
let hasher = Cc["@mozilla.org/security/hash;1"]. let hasher = Cc["@mozilla.org/security/hash;1"].
createInstance(Ci.nsICryptoHash); createInstance(Ci.nsICryptoHash);
hasher.init(hasher.SHA1); hasher.init(hasher.SHA1);
@ -274,6 +270,9 @@ function getPerInstallationMutexName(aGlobal = true) {
hasher.update(data, data.length); hasher.update(data, data.length);
return (aGlobal ? "Global\\" : "") + "MozillaUpdateMutex-" + hasher.finish(true); return (aGlobal ? "Global\\" : "") + "MozillaUpdateMutex-" + hasher.finish(true);
#else
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
#endif
} }
/** /**
@ -285,13 +284,14 @@ function getPerInstallationMutexName(aGlobal = true) {
* @return true if this instance holds the update mutex * @return true if this instance holds the update mutex
*/ */
function hasUpdateMutex() { function hasUpdateMutex() {
if (AppConstants.platform != "win") { #ifdef XP_WIN
return true;
}
if (!gUpdateMutexHandle) { if (!gUpdateMutexHandle) {
gUpdateMutexHandle = createMutex(getPerInstallationMutexName(true), false); gUpdateMutexHandle = createMutex(getPerInstallationMutexName(true), false);
} }
return !!gUpdateMutexHandle; return !!gUpdateMutexHandle;
#else
return true;
#endif
} }
/** /**
@ -322,10 +322,7 @@ function areDirectoryEntriesWriteable(aDir) {
* @return true if elevation is required, false otherwise * @return true if elevation is required, false otherwise
*/ */
function getElevationRequired() { function getElevationRequired() {
if (AppConstants.platform != "macosx") { #ifdef XP_MACOSX
return false;
}
try { try {
// Recursively check that the application bundle (and its descendants) can // Recursively check that the application bundle (and its descendants) can
// be written to. // be written to.
@ -344,6 +341,7 @@ function getElevationRequired() {
} }
LOG("getElevationRequired - able to write to application bundle, elevation " + LOG("getElevationRequired - able to write to application bundle, elevation " +
"not required"); "not required");
#endif
return false; return false;
} }
@ -355,85 +353,86 @@ function getElevationRequired() {
* @return true if an update can be applied, false otherwise * @return true if an update can be applied, false otherwise
*/ */
function getCanApplyUpdates() { function getCanApplyUpdates() {
if (AppConstants.platform != "macosx") { #ifndef XP_MACOSX
try { try {
let updateTestFile = getUpdateFile([FILE_UPDATE_TEST]); let updateTestFile = getUpdateFile([FILE_UPDATE_TEST]);
LOG("getCanApplyUpdates - testing write access " + updateTestFile.path); LOG("getCanApplyUpdates - testing write access " + updateTestFile.path);
testWriteAccess(updateTestFile, false); testWriteAccess(updateTestFile, false);
if (AppConstants.platform == "win") {
// Example windowsVersion: Windows XP == 5.1
let windowsVersion = Services.sysinfo.getProperty("version");
LOG("getCanApplyUpdates - windowsVersion = " + windowsVersion);
/** #ifdef XP_WIN
* For Vista, updates can be performed to a location requiring admin // Example windowsVersion: Windows XP == 5.1
* privileges by requesting elevation via the UAC prompt when launching let windowsVersion = Services.sysinfo.getProperty("version");
* updater.exe if the appDir is under the Program Files directory LOG("getCanApplyUpdates - windowsVersion = " + windowsVersion);
* (e.g. C:\Program Files\) and UAC is turned on and we can elevate
* (e.g. user has a split token).
*
* Note: this does note attempt to handle the case where UAC is turned on
* and the installation directory is in a restricted location that
* requires admin privileges to update other than Program Files.
*/
let userCanElevate = false;
if (parseFloat(windowsVersion) >= 6) { /**
try { * For Vista, updates can be performed to a location requiring admin
// KEY_UPDROOT will fail and throw an exception if * privileges by requesting elevation via the UAC prompt when launching
// appDir is not under the Program Files, so we rely on that * updater.exe if the appDir is under the Program Files directory
let dir = Services.dirsvc.get(KEY_UPDROOT, Ci.nsIFile); * (e.g. C:\Program Files\) and UAC is turned on and we can elevate
// appDir is under Program Files, so check if the user can elevate * (e.g. user has a split token).
userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper). *
userCanElevate; * Note: this does note attempt to handle the case where UAC is turned on
LOG("getCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate); * and the installation directory is in a restricted location that
} * requires admin privileges to update other than Program Files.
catch (ex) { */
// When the installation directory is not under Program Files, let userCanElevate = false;
// fall through to checking if write access to the
// installation directory is available.
LOG("getCanApplyUpdates - on Vista, appDir is not under Program Files");
}
}
/** if (parseFloat(windowsVersion) >= 6) {
* On Windows, we no longer store the update under the app dir. try {
* // KEY_UPDROOT will fail and throw an exception if
* If we are on Windows (including Vista, if we can't elevate) we need to // appDir is not under the Program Files, so we rely on that
* to check that we can create and remove files from the actual app let dir = Services.dirsvc.get(KEY_UPDROOT, Ci.nsIFile);
* directory (like C:\Program Files\Mozilla Firefox). If we can't // appDir is under Program Files, so check if the user can elevate
* (because this user is not an adminstrator, for example) canUpdate() userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).
* should return false. userCanElevate;
* LOG("getCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate);
* For Vista, we perform this check to enable updating the application }
* when the user has write access to the installation directory under the catch (ex) {
* following scenarios: // When the installation directory is not under Program Files,
* 1) the installation directory is not under Program Files // fall through to checking if write access to the
* (e.g. C:\Program Files) // installation directory is available.
* 2) UAC is turned off LOG("getCanApplyUpdates - on Vista, appDir is not under Program Files");
* 3) UAC is turned on and the user is not an admin
* (e.g. the user does not have a split token)
* 4) UAC is turned on and the user is already elevated, so they can't be
* elevated again
*/
if (!userCanElevate) {
// if we're unable to create the test file this will throw an exception.
let appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_UPDATE_TEST);
LOG("getCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists()) {
appDirTestFile.remove(false);
}
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
}
} }
} catch (e) {
LOG("getCanApplyUpdates - unable to apply updates. Exception: " + e);
// No write privileges to install directory
return false;
} }
}
/**
* On Windows, we no longer store the update under the app dir.
*
* If we are on Windows (including Vista, if we can't elevate) we need to
* to check that we can create and remove files from the actual app
* directory (like C:\Program Files\Mozilla Firefox). If we can't
* (because this user is not an adminstrator, for example) canUpdate()
* should return false.
*
* For Vista, we perform this check to enable updating the application
* when the user has write access to the installation directory under the
* following scenarios:
* 1) the installation directory is not under Program Files
* (e.g. C:\Program Files)
* 2) UAC is turned off
* 3) UAC is turned on and the user is not an admin
* (e.g. the user does not have a split token)
* 4) UAC is turned on and the user is already elevated, so they can't be
* elevated again
*/
if (!userCanElevate) {
// if we're unable to create the test file this will throw an exception.
let appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_UPDATE_TEST);
LOG("getCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists()) {
appDirTestFile.remove(false);
}
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
}
#endif // XP_WIN
} catch (e) {
LOG("getCanApplyUpdates - unable to apply updates. Exception: " + e);
// No write privileges to install directory
return false;
}
#endif // !XP_MACOSX
LOG("getCanApplyUpdates - able to apply updates"); LOG("getCanApplyUpdates - able to apply updates");
return true; return true;
@ -454,27 +453,29 @@ XPCOMUtils.defineLazyGetter(this, "gCanStageUpdatesSession", function aus_gCSUS(
try { try {
let updateTestFile; let updateTestFile;
if (AppConstants.platform == "macosx") { #ifdef XP_MACOSX
updateTestFile = getUpdateFile([FILE_UPDATE_TEST]); updateTestFile = getUpdateFile([FILE_UPDATE_TEST]);
} else { #else
updateTestFile = getInstallDirRoot(); updateTestFile = getInstallDirRoot();
updateTestFile.append(FILE_UPDATE_TEST); updateTestFile.append(FILE_UPDATE_TEST);
} #endif
LOG("gCanStageUpdatesSession - testing write access " + LOG("gCanStageUpdatesSession - testing write access " +
updateTestFile.path); updateTestFile.path);
testWriteAccess(updateTestFile, true); testWriteAccess(updateTestFile, true);
if (AppConstants.platform != "macosx") {
// On all platforms except Mac, we need to test the parent directory as #ifndef XP_MACOSX
// well, as we need to be able to move files in that directory during the // On all platforms except Mac, we need to test the parent directory as
// replacing step. // well, as we need to be able to move files in that directory during the
updateTestFile = getInstallDirRoot().parent; // replacing step.
updateTestFile.append(FILE_UPDATE_TEST); updateTestFile = getInstallDirRoot().parent;
LOG("gCanStageUpdatesSession - testing write access " + updateTestFile.append(FILE_UPDATE_TEST);
updateTestFile.path); LOG("gCanStageUpdatesSession - testing write access " +
updateTestFile.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE, updateTestFile.path);
FileUtils.PERMS_DIRECTORY); updateTestFile.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE,
updateTestFile.remove(false); FileUtils.PERMS_DIRECTORY);
} updateTestFile.remove(false);
#endif // !XP_MACOSX
} catch (e) { } catch (e) {
LOG("gCanStageUpdatesSession - unable to stage updates. Exception: " + LOG("gCanStageUpdatesSession - unable to stage updates. Exception: " +
e); e);
@ -593,10 +594,10 @@ function getAppBaseDir() {
*/ */
function getInstallDirRoot() { function getInstallDirRoot() {
let dir = getAppBaseDir(); let dir = getAppBaseDir();
if (AppConstants.platform == "macosx") { #ifdef XP_MACOSX
// On Mac, we store the Updated.app directory inside the bundle directory. // On Mac, we store the Updated.app directory inside the bundle directory.
dir = dir.parent.parent; dir = dir.parent.parent;
} #endif
return dir; return dir;
} }
@ -879,31 +880,33 @@ function handleUpdateFailure(update, errorCode) {
let cancelations = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS, 0); let cancelations = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS, 0);
cancelations++; cancelations++;
Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS, cancelations); Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS, cancelations);
if (AppConstants.platform == "macosx") {
let osxCancelations = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX, 0); #ifdef XP_MACOSX
osxCancelations++; let osxCancelations = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX, 0);
Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX, osxCancelations++;
osxCancelations); Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX,
let maxCancels = Services.prefs.getIntPref( osxCancelations);
PREF_APP_UPDATE_CANCELATIONS_OSX_MAX, let maxCancels = Services.prefs.getIntPref(
DEFAULT_CANCELATIONS_OSX_MAX); PREF_APP_UPDATE_CANCELATIONS_OSX_MAX,
// Prevent the preference from setting a value greater than 5. DEFAULT_CANCELATIONS_OSX_MAX);
maxCancels = Math.min(maxCancels, 5); // Prevent the preference from setting a value greater than 5.
if (osxCancelations >= maxCancels) { maxCancels = Math.min(maxCancels, 5);
cleanupActiveUpdate(); if (osxCancelations >= maxCancels) {
} else { cleanupActiveUpdate();
writeStatusFile(getUpdatesDir(),
update.state = STATE_PENDING_ELEVATE);
}
update.statusText = gUpdateBundle.GetStringFromName("elevationFailure");
update.QueryInterface(Ci.nsIWritablePropertyBag);
update.setProperty("patchingFailed", "elevationFailure");
let prompter = Cc["@mozilla.org/updates/update-prompt;1"].
createInstance(Ci.nsIUpdatePrompt);
prompter.showUpdateError(update);
} else { } else {
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING); writeStatusFile(getUpdatesDir(),
update.state = STATE_PENDING_ELEVATE);
} }
update.statusText = gUpdateBundle.GetStringFromName("elevationFailure");
update.QueryInterface(Ci.nsIWritablePropertyBag);
update.setProperty("patchingFailed", "elevationFailure");
let prompter = Cc["@mozilla.org/updates/update-prompt;1"].
createInstance(Ci.nsIUpdatePrompt);
prompter.showUpdateError(update);
#else
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
#endif
return true; return true;
} }
@ -1483,12 +1486,15 @@ UpdateService.prototype = {
Services.obs.removeObserver(this, topic); Services.obs.removeObserver(this, topic);
Services.prefs.removeObserver(PREF_APP_UPDATE_LOG, this); Services.prefs.removeObserver(PREF_APP_UPDATE_LOG, this);
if (AppConstants.platform == "win" && gUpdateMutexHandle) { #ifdef XP_WIN
if (gUpdateMutexHandle) {
// If we hold the update mutex, let it go! // If we hold the update mutex, let it go!
// The OS would clean this up sometime after shutdown, // The OS would clean this up sometime after shutdown,
// but that would have no guarantee on timing. // but that would have no guarantee on timing.
closeHandle(gUpdateMutexHandle); closeHandle(gUpdateMutexHandle);
} }
#endif
if (this._retryTimer) { if (this._retryTimer) {
this._retryTimer.cancel(); this._retryTimer.cancel();
} }
@ -1845,7 +1851,8 @@ UpdateService.prototype = {
}); });
let update = minorUpdate || majorUpdate; let update = minorUpdate || majorUpdate;
if (AppConstants.platform == "macosx" && update) { #ifdef XP_MACOSX
if (update) {
if (getElevationRequired()) { if (getElevationRequired()) {
let installAttemptVersion = Services.prefs.getCharPref( let installAttemptVersion = Services.prefs.getCharPref(
PREF_APP_UPDATE_ELEVATE_VERSION, PREF_APP_UPDATE_ELEVATE_VERSION,
@ -1895,6 +1902,7 @@ UpdateService.prototype = {
} }
} }
} }
#endif
return update; return update;
}, },
@ -2890,11 +2898,11 @@ Downloader.prototype = {
LOG("Downloader:_verifyDownload downloaded size == expected size."); LOG("Downloader:_verifyDownload downloaded size == expected size.");
#ifdef MOZ_VERIFY_MAR_SIGNATURE
// The hash check is not necessary when mar signatures are used to verify // The hash check is not necessary when mar signatures are used to verify
// the downloaded mar file. // the downloaded mar file.
if (AppConstants.MOZ_VERIFY_MAR_SIGNATURE) { return true;
return true; #endif
}
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream); createInstance(Ci.nsIFileInputStream);