tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 18ae2eefe6fd9ab3a2c856c498b4cc878e09e75f
parent 5f8128535c83d8a45d862cfe1fc1c484ea183c45
Author: Dave Townsend <dtownsend@oxymoronical.com>
Date:   Fri,  9 Jan 2026 13:46:50 +0000

Bug 2004469: Avoid using the remoting service when opening external links in the currently running profile. r=profiles-reviewers,jhirsch

Differential Revision: https://phabricator.services.mozilla.com/D277601

Diffstat:
Mbrowser/components/profiles/SelectableProfileService.sys.mjs | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/profiles/tests/unit/test_command_line_handler.js | 38++++++++++++++++++++++----------------
2 files changed, 70 insertions(+), 16 deletions(-)

diff --git a/browser/components/profiles/SelectableProfileService.sys.mjs b/browser/components/profiles/SelectableProfileService.sys.mjs @@ -1669,10 +1669,58 @@ export class CommandLineHandler { return null; } + /** + * Attempts to parse the arguments expected when opening URLs from other + * applications on macOS. + * + * @param {Array<string>} args The command line arguments. + * @returns {boolean} True if the arguments matched the expected form. + */ + openUrls(args) { + // Arguments are expected to be in pairs of "-url" "<url>". + if (args.length % 2 != 0) { + return false; + } + + for (let i = 0; i < args.length; i += 2) { + if (args[i] != "-url") { + return false; + } + } + + // Now the arguments are verified to only be "-url" arguments we can pass + // them directly to the only handler for those arguments. + let workingDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile); + let cmdLine = Cu.createCommandLine( + args, + workingDir, + Ci.nsICommandLine.STATE_REMOTE_EXPLICIT + ); + + try { + let handler = Cc["@mozilla.org/browser/final-clh;1"].createInstance( + Ci.nsICommandLineHandler + ); + handler.handle(cmdLine); + } catch (e) { + console.error(e); + return false; + } + + return true; + } + async redirectCommandLine(args) { let defaultPath = await this.findDefaultProfilePath(); if (defaultPath) { + if ( + defaultPath == SelectableProfileService.currentProfile.path && + this.openUrls(args) + ) { + return; + } + // Attempt to use the remoting service to send the arguments to any // existing instance of this profile (this even works for the current // instance on macOS which is the only platform we call this for). diff --git a/browser/components/profiles/tests/unit/test_command_line_handler.js b/browser/components/profiles/tests/unit/test_command_line_handler.js @@ -9,6 +9,7 @@ const { sinon } = ChromeUtils.importESModule( const execProcess = sinon.stub(); const sendCommandLine = sinon.stub().throws(Cr.NS_ERROR_NOT_AVAILABLE); +const commandLineHandler = sinon.stub(); add_setup(async () => { await initSelectableProfileService(); @@ -19,6 +20,12 @@ add_setup(async () => { (path, args, raise) => sendCommandLine(path, [...args], raise) ); sinon.replace(getSelectableProfileService(), "execProcess", execProcess); + + let { nsDefaultCommandLineHandler: browserClh } = ChromeUtils.importESModule( + "resource:///modules/BrowserContentHandler.sys.mjs" + ); + + sinon.replace(browserClh.prototype, "handle", commandLineHandler); }); function nextCall(stub) { @@ -89,29 +96,28 @@ add_task(async function test_redirect_args() { "Should have prevented the default handler" ); - await nextCall(execProcess); + await nextCall(commandLineHandler); Assert.equal( - sendCommandLine.callCount, + commandLineHandler.callCount, 1, - "Should have attempted to remote once" - ); - Assert.deepEqual( - sendCommandLine.firstCall.args, - [profilePath, ["-url", "https://www.google.com/"], true], - "should have used the right arguments" + "Should have called the main browser command line handler directly" ); - sendCommandLine.resetHistory(); - - Assert.equal(execProcess.callCount, 1, "Should have attempted to exec once"); - Assert.deepEqual( - execProcess.firstCall.args, - [["-foreground", "-url", "https://www.google.com/"]], - "should have used the right arguments" + let [generatedCmdLine] = commandLineHandler.firstCall.args; + Assert.equal( + generatedCmdLine.length, + 2, + "Should have generated a command line with the correct number of arguments" + ); + Assert.equal(generatedCmdLine.getArgument(0), "-url"); + Assert.equal( + generatedCmdLine.getArgument(1), + "https://www.google.com/", + "Should have generated a command line with the correct URL" ); - execProcess.resetHistory(); + commandLineHandler.resetHistory(); let profileData = readProfilesIni();