Unset Mozilla environment variables when launching files and URLs (#4983)

Fixes #4981
This commit is contained in:
Dan Stillman 2025-01-21 05:40:27 -05:00 • committed by GitHub
parent a4414cc2f0
commit 296edc3fdd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 128 additions and 3 deletions

View file

@ -149,6 +149,7 @@ Zotero.FileHandlers = {
handler = handler || systemHandler;
if (handler) {
if (Zotero.isMac) {
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
try {
await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', handler, path]);
return true;
@ -156,6 +157,9 @@ Zotero.FileHandlers = {
catch (e) {
Zotero.logError(e);
}
finally {
Zotero.Utilities.Internal.Environment.restoreMozillaVariables();
}
}
try {
@ -498,8 +502,13 @@ Zotero.FileHandlers = {
if (!Zotero.File.pathToFile(command).isExecutable()) {
throw new Error(`${command} is not an executable`);
}
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
// Do not await
Zotero.Utilities.Internal.exec(command, args);
var promise = Zotero.Utilities.Internal.exec(command, args);
promise.finally(() => Zotero.Utilities.Internal.Environment.restoreMozillaVariables());
},
};

View file

@ -2899,6 +2899,85 @@ Zotero.Utilities.Internal.getProcessID = function () {
};
Zotero.Utilities.Internal.Environment = {
/**
* Unset an environment variable
*
* Since nsIEnvironment doesn't have an unset method
*/
unset: function (varName) {
Components.utils.import("resource://gre/modules/ctypes.jsm");
let lib;
let result;
let success;
// Windows
// https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew
if (Zotero.isWin) {
lib = ctypes.open("kernel32.dll");
let SetEnvironmentVariable = lib.declare(
"SetEnvironmentVariableW",
ctypes.winapi_abi,
ctypes.int, // Return type
ctypes.char16_t.ptr, // Argument type: LPCTSTR (variable name)
ctypes.char16_t.ptr // Argument type: LPCTSTR (value, NULL to unset)
);
result = SetEnvironmentVariable(varName, null);
success = result != 0; // "If the function succeeds, the return value is nonzero."
}
// macOS or Linux
else {
lib = ctypes.open(Zotero.isMac ? "/usr/lib/libSystem.dylib" : "libc.so.6");
let unsetenv = lib.declare(
"unsetenv",
ctypes.default_abi,
ctypes.int, // Return type
ctypes.char.ptr // Argument type: const char *
);
result = unsetenv(varName);
success = result == 0;
}
// Check the result
if (success) {
//Zotero.debug(`Unset environment variable ${varName}`);
}
else {
Zotero.logError(`Failed to unset environment variable ${varName} (${result})`);
}
lib.close();
},
/**
* Clear the Mozilla environment variables that we changed in the launcher
*
* Call this before launching another process that might be Firefox so that we don't end up
* using the wrong Firefox profile when launching URLs or PDFs. On Windows, it's not necessary
* to call this when launching URLs, only processes.
*
* https://github.com/zotero/zotero/issues/4981
*/
clearMozillaVariables: function () {
this.unset("MOZ_ALLOW_DOWNGRADE");
this.unset("MOZ_LEGACY_PROFILES");
},
/**
* Re-set the Mozilla environment variables that we changed in the launcher
*
* Call this in a finally() after using unsetMozillaVariables(). This mostly isn't necessary,
* since most new launches of Zotero would use the modified launcher, but a restart on Linux
* skips our shell script where we set these variables.
*/
restoreMozillaVariables: function () {
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
env.set("MOZ_ALLOW_DOWNGRADE", "1");
env.set("MOZ_LEGACY_PROFILES", "1");
},
};
/**
* Base64 encode / decode
* From http://www.webtoolkit.info/

View file

@ -992,6 +992,9 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
*/
this.launchFile = function (file) {
file = Zotero.File.pathToFile(file);
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
try {
Zotero.debug("Launching " + file.path);
file.launch();
@ -1034,6 +1037,9 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
);
}
}
finally {
Zotero.Utilities.Internal.Environment.restoreMozillaVariables();
}
};
@ -1058,8 +1064,12 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
args = [filePath];
}
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
// Async, but we don't want to block
Zotero.Utilities.Internal.exec(applicationPath, args);
var promise = Zotero.Utilities.Internal.exec(applicationPath, args);
promise.finally(() => Zotero.Utilities.Internal.Environment.restoreMozillaVariables());
};
@ -1089,12 +1099,29 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
if (!found.value) {
throw new Error(`Handler not found for '${scheme}' URLs`);
}
svc.loadURI(Services.io.newURI(url, null, null));
try {
if (!Zotero.isWin) {
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
}
svc.loadURI(Services.io.newURI(url, null, null));
}
finally {
if (!Zotero.isWin) {
Zotero.Utilities.Internal.Environment.restoreMozillaVariables();
}
}
return;
}
}
var mozCleared = false;
try {
if (!Zotero.isWin) {
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
mozCleared = true;
}
var uri = Services.io.newURI(url, null, null);
var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
.getService(Components.interfaces.nsIExternalProtocolService)
@ -1119,6 +1146,11 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
+ "check extensions.zotero." + pref + " in about:config");
}
if (!mozCleared) {
Zotero.Utilities.Internal.Environment.clearMozillaVariables();
mozCleared = true;
}
var proc = Components.classes["@mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess);
proc.init(exec);
@ -1126,6 +1158,11 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
var args = [url];
proc.runw(false, args, args.length);
}
finally {
if (mozCleared) {
Zotero.Utilities.Internal.Environment.restoreMozillaVariables();
}
}
}