Opened 3 years ago

Closed 3 years ago

Last modified 12 months ago

#11429 closed defect (fixed)

meek-http-helper opens up a second dock icon

Reported by: dcf Owned by: dcf
Priority: Medium Milestone:
Component: Obfuscation/meek Version:
Severity: Keywords:
Cc: Actual Points:
Parent ID: Points:
Reviewer: Sponsor:

Description

The second copy of firefox that is started by meek-client-torbrowser brings up a second Tor Browser dock icon on OS X. Better if we can find a way to hide it.

Something similar happens on Windows, but it doesn't look as bad because the icons appear in a little stack.

Child Tickets

Attachments (2)

3.6.1-meek-1-two-icons.png (14.9 KB) - added by dcf 3 years ago.
A screenshot of the two icons showing up in the dock.
meek-http-helper-ctypes-icon.gif (89.8 KB) - added by dcf 3 years ago.
Momentary appearance of a dock icon when turning off the icon at runtime using ctypes as in comment:8.

Download all attachments as: .zip

Change History (14)

comment:1 Changed 3 years ago by dcf

True as of tbb-3.5.2.1-meek-4.

comment:2 Changed 3 years ago by dcf

Since 2f753a57ea there's no second icon on Windows, but there is still on OS X.

comment:3 follow-up: Changed 3 years ago by lunar

I'm not sure what has been tried already. It seems that a dedicated plist that would set LSUIElement to 1 would get the desired effect.

https://developer.apple.com/library/mac/documentation/general/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/20001431-108256

comment:4 Changed 3 years ago by lunar

It might also be doable with code only starting from 10.7:
https://stackoverflow.com/a/12105105

comment:5 in reply to: ↑ 3 Changed 3 years ago by dcf

Replying to lunar:

I'm not sure what has been tried already. It seems that a dedicated plist that would set LSUIElement to 1 would get the desired effect.

https://developer.apple.com/library/mac/documentation/general/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/20001431-108256

Thanks for this hint. Inside of TorBrowser.app, there is another app directory, Contents/MacOS/TorBrowser.app, which is the one that actually contains the firefox executable. If I edit Contents/MacOS/TorBrowser.app/Info.plist to add

<key>LSUIElement</key>
<true/>

it almost works—the headless browser doesn't show an icon, but the main browser doesn't, either. I did a lot of searching and didn't find a very nice solution. However I did find an ugly solution: Make a second copy of TorBrowser.app called TorBrowser.app-headless that symlinks all files to the first copy, all files except Info.plist. Set LSUIElement only in the second copy's Info.plist. Set up meek-client-torbrowser to point to TorBrowser.app-headless. To wit:

Contents/MacOS/TorBrowser.app/Contents:
-rw-r-----@  1 david  staff  5540 Dec 31  1999 Info.plist
drwxr-x---@ 25 david  staff   850 Dec 31  1999 MacOS
-rw-r-----@  1 david  staff     8 Dec 31  1999 PkgInfo
drwxr-x---@  5 david  staff   170 Dec 31  1999 Resources

Contents/MacOS/TorBrowser.app-headless/Contents:
-rw-r-----@ 1 david  staff  5572 May 11 13:07 Info.plist
lrwxr-xr-x  1 david  staff    35 May 11 13:06 MacOS -> ../../TorBrowser.app/Contents/MacOS
lrwxr-xr-x  1 david  staff    37 May 11 13:06 PkgInfo -> ../../TorBrowser.app/Contents/PkgInfo
lrwxr-xr-x  1 david  staff    39 May 11 13:06 Resources -> ../../TorBrowser.app/Contents/Resources

This way is fairly dumb but it looks as if it will work if we can't think of anything better. I looked for a way to start an app with an alternate or override Info.plist file, and didn't find anything.

Changed 3 years ago by dcf

A screenshot of the two icons showing up in the dock.

comment:6 Changed 3 years ago by dcf

A screenshot of the two icons showing up in the dock.

Here's a screenshot of the bug, as rue for remembrance after it gets fixed. The icon on the left is the actual browser that you interact with; the one on the right is the headless one without a menu bar that does nothing when you click on it.

comment:7 Changed 3 years ago by lunar

I believe the following two C statements could be “called” using JS ctypes:

ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToUIElementApplication);

See Processes.h.

comment:8 follow-up: Changed 3 years ago by lunar

Other examples: `hideMacDockIcon()` in Python, `showMacDockIcon()` in Python

The following piece of code is absolutely untested but should help:

Components.utils.import("resource://gre/modules/ctypes.jsm");

var carbon = ctypes.open("/System/Library/Frameworks/Carbon.framework/Carbon");

/* MacTypes.h */
var OSStatus = ctypes.c_int32;

/* Processes.h
 *
 * struct ProcessSerialNumber {
 *   unsigned long highLongOfPSN;
 *   unsigned long lowLongOfPSN;
 * };
 *
 * enum {
 *   kNoProcess = 0,
 *   kSystemProcess = 1,
 *   kCurrentProcess = 2
 * };
 */

var ProcessSerialNumber = ctypes.StructType("ProcessSerialNumber",
                                            [ { "highLongOfPSN": ctypes.unsigned_long,
                                                "lowLongOfPSN": ctypes.unsigned_long,
                                              } ]);
var kCurrentProcess = 2;

/* Processes.h
 *
 * enum {
 *   kProcessTransformToForegroundApplication = 1L,
 *   kProcessTransformToBackgroundApplication = 2L,
 *   kProcessTransformToUIElementApplication = 4L,
 * };
 * typedef UInt32 ProcessApplicationTransformState;
 */

var ProcessApplicationTransformState = ctypes.uint32_t;
var kProcessTransformToUIElementApplication = 4;

/* Processes.h
 *
 * OSStatus TransformProcessType (
 *   const ProcessSerialNumber *psn,
 *   ProcessApplicationTransformState transformState
 * );
 */
var TransformProcessType = carbon.declare("TransformProcessType",
                                          ctypes.default_abi,
                                          OSStatus /* return type */,
                                          ProcessSerialNumber.ptr,
                                          ProcessApplicationTransformState);

var psn = ProcessSerialNumber();
psn.highLongOfPSN = 0;
psn.lowLongOfPSN = kCurrentProcess;

r = TransformProcessType(psn, kProcessTransformToUIElementApplication)
console.log("TransformProcessType returned " + r);

carbon.close();

Last edited 3 years ago by lunar (previous) (diff)

Changed 3 years ago by dcf

Momentary appearance of a dock icon when turning off the icon at runtime using ctypes as in comment:8.

comment:9 in reply to: ↑ 8 Changed 3 years ago by dcf

Replying to lunar:

Other examples: `hideMacDockIcon()` in Python, `showMacDockIcon()` in Python

The following piece of code is absolutely untested but should help:

Thanks for this code. I had to made these changes to get it to run:

--- main.js.orig        2014-05-24 10:09:42.000000000 -0700
+++ main.js     2014-05-24 10:10:16.000000000 -0700
@@ -63,7 +63,7 @@
 var carbon = ctypes.open("/System/Library/Frameworks/Carbon.framework/Carbon");

 /* MacTypes.h */
-var OSStatus = ctypes.c_int32;
+var OSStatus = ctypes.int32_t;

 /* Processes.h
  *
@@ -80,9 +80,8 @@
  */

 var ProcessSerialNumber = ctypes.StructType("ProcessSerialNumber",
-                                            [ { "highLongOfPSN": ctypes.unsigned_long,
-                                                "lowLongOfPSN": ctypes.unsigned_long,
-                                              } ]);
+                                            [ { "highLongOfPSN": ctypes.unsigned_long },
+                                              { "lowLongOfPSN": ctypes.unsigned_long } ]);
 var kCurrentProcess = 2;

 /* Processes.h
@@ -115,8 +114,8 @@
 psn.highLongOfPSN = 0;
 psn.lowLongOfPSN = kCurrentProcess;

-r = TransformProcessType(psn, kProcessTransformToUIElementApplication)
-console.log("TransformProcessType returned " + r);
+r = TransformProcessType(psn.address(), kProcessTransformToUIElementApplication);
+dump("TransformProcessType returned " + r + "\n");

 carbon.close();

The code works to disable the icon, but the problem is that the icon has already started appearing by the time the code starts to hide it. It's not always as obvious as this animation shows it; sometimes it only gets a few pixels wide before it disappears. (Here's I'm starting the meek-http-helper profile manually; normally there would be another Tor Browser icon to the left of the one that appears and disappears.)

Momentary appearance of a dock icon when turning off the icon at runtime using ctypes as in comment:8.

I think I'll try the Info.plist approach, so the icon is hidden from startup. Something similar is going on, apart from the meek helper, in #12121.

comment:10 follow-up: Changed 3 years ago by dcf

  • Status changed from new to needs_review

Here's a proposed patch that works. I invite comment on it.

I'll copy the commit log here.

This is an implementation of the icon-hiding idea from https://trac.torproject.org/projects/tor/ticket/11429#comment:5. The Info.plist file enables us to control whether an icon appears, but I could find no way to override the values we need at run time. So instead we create a copy of the original bundle directory, with the only difference being the contents of Info.plist. (The "copy" is actually a few symlinks, so it doesn't take much space.)

The shallow directory copy is in a directory named TorBrowser.app.meek-http-helper. I made the name not end in ".app" so that you can't open it as a bundle by accident from the Finder. I put a README in the bundle directory explaining why the directory exists.

There's a new build helper, background-plist.py, which deletes the LSUIElement key (if present) and sets LSBackgroundOnly=true. This is more robust than a sed script that inserts a LSBackgroundOnly key somewhere in the XML, because the same key could be already set, or LSUIElement have a contradictory value, elsewhere in the file.

I chose to set the key LSBackgroundOnly, rather than the LSUIElement we've discussed so far, though both of them work in terms of hiding the icon. I made this decision based only on the documentation for the two keys, which makes LSBackgroundOnly sound more background-y.

LSUIElement

LSUIElement specifies whether the app runs as an agent app. If this key is set to “1”, Launch Services runs the app as an agent app. Agent apps do not appear in the Dock or in the Force Quit window. Although they typically run as background apps, they can come to the foreground to present a user interface if desired. A click on a window belonging to an agent app brings that app forward to handle events.

LSBackgroundOnly

LSBackgroundOnly specifies whether this app runs only in the background. If this key exists and is set to “1”, Launch Services runs the app in the background only. You can use this key to create faceless background apps. You should also use this key if your app uses higher-level frameworks that connect to the window server, but are not intended to be visible to users. Background apps must be compiled as Mach-O executables.

The patch adds exactly these new files to the mac bundle:

$ ls -lR Contents/MacOS/TorBrowser.app.meek-http-helper
total 8
drwxr-x---@ 6 david  staff  204 May 24 16:04 Contents
-rw-r-----@ 1 david  staff  672 Dec 31  1999 README

Contents/MacOS/TorBrowser.app.meek-http-helper/Contents:
total 40
-rw-r-----@ 1 david  staff  5563 Dec 31  1999 Info.plist
lr-xr-xr-x  1 david  staff    35 Dec 31  1999 MacOS -> ../../TorBrowser.app/Contents/MacOS
lr-xr-xr-x  1 david  staff    37 Dec 31  1999 PkgInfo -> ../../TorBrowser.app/Contents/PkgInfo
lr-xr-xr-x  1 david  staff    39 Dec 31  1999 Resources -> ../../TorBrowser.app/Contents/Resources
Last edited 12 months ago by dcf (previous) (diff)

comment:11 in reply to: ↑ 10 Changed 3 years ago by dcf

  • Resolution set to fixed
  • Status changed from needs_review to closed

Replying to dcf:

Here's a proposed patch that works. I invite comment on it.

3.6.1-meek-2 bundles are built with this patch, and it works like a charm. I'm calling it fixed. We'll see what the TBB maintainers have to say about the symlinks when the larger meek patch is merged in #10935.

Last edited 12 months ago by dcf (previous) (diff)

comment:12 Changed 3 years ago by mcs

I filed a new bug about supporting symlinks in the Firefox updater: #12647

Note: See TracTickets for help on using tickets.