Integrate snapd-xdg-open into snapd repository

The xdg-open binary will stay as is and will still allow you to do what it currently does. What we want to change is below xdg-open. So in a best case no application ever notice that we changed the backend implementation of this :slight_smile:

1 Like

To follow up on this, I am working on two electron apps and have been going around Github looking at others that can be snapped up and submitted tothe store. (I also have been helping some bigger companies get on the band wagon).

I think this should be moved to a top priority to ensure that those looking to move these critical apps find that all their features are well supported upon landing.

1 Like

Just to make things clear: snapd-xdg-open exists on Ubuntu 16.04 and 14.04 already today and gives you the functionality weā€™re talking about here out of the box. @niemeyer asked me to not take snapd-xdg-open further to other distributions (Fedora, openSUSE, ā€¦) until we reworked the basic design. Nevertheless, as we donā€™t have snapd officially on these distributions yet this can be considered a bug for them we will fix in the near future. For your electron apps it should be possible out-of-the-box today to ask via xdg-open (which is a standard Linux desktop thing and nothing we invented) to open webpages in the system default webbrowser. If that doesnā€™t work we have a bug.

1 Like

the bug is that we can not easily add a hard dependency to snapd for it (people running apt-get upgrade instead of dist-upgrade get dependency errors, we get bugs ā€¦) which means that derivatives/flavours that do not seed it explicitly do not get snapd-xdg-open currently.
the plan was initially to simply include snapd-xdg-open in the snapd package to overcome this issue.

@niemeyer I am thinking about this now for some time. Let me summarize where we are and what my thoughts on this are so far:

As of today xdg-open calls dbus-send today which sends a call to snapd-xdg-open which runs in the context of the session of the user executing xdg-open. If root calls xdg-open the dbus-send call will go nowhere as root doesnā€™t have a dbus session bus. snapd-xdg-open calls g_app_info_launch_default_for_uri which only makes sense in the context of a user session. It uses the MIME database to find the right application to execute for a given URI.

Your proposal is now to add a subcommand to snapctl which will handle a given link. This fine so far. However, if snapctl is called from the context of a user session we loose all user session information once the REST API call arrives at snapd. We then have no further way to translate the call back to the calling user-session. As the call to g_app_info_launch_default_for_uri needs to be initiated from within a user session and in the unconfined area we canā€™t do this from within snapd.

To solve this problem we need something running inside the user session which we can pass the link a snap gives to snapctl open-link to. Until now this was snapd-xdg-open. If we donā€™t want this to be named snapd-xdg-open anymore we could invent something like snapd --user which runs inside a user session (started by upstart on 16.04 or systemd --user on other distributions). snapd --user would then keep a connection to snapd to receive further instructions like an open-link command from snapctl which it then would pass this over to either the real xdg-open binary on the host or g_app_info_launch_default_for_uri. With this we still need something we can use inside snapd to identify a snapd --user instance from a snapctl call.

Actually we donā€™t need to have snapctl talking with the systemd snapd it could also talk with the session snapd --user instance directly over dbus or a socket.

@morphis I havenā€™t searched yet, but Iā€™d be extremely surprised if a process with complete access to the whole system has no way to open a link in a browser.

The problem here is not the level of access to the system, it is how it is mapped into the right user session. I am not sure if a crappy su - $USER will suffice this use case.

Still, the point is that you have the whole machine at hand. There ought to be a very simple way to make this work.

As explained above, what all system services like NetworkManager/connman (e.g. requesting passwords, opening a website for captive portals), BlueZ (e.g. PIN/passcode, authorization or per user media playback control) are doing is: They delegate the actual ā€œOpenBrowserā€ action to an agent running as part of the user session. This agent then has the responsibility to process the received action as needed and open a web browser for example. In Ubuntu or gnome this for example is done by nm-applet for NetworkManager or the bluetooth applet for BlueZ.

I donā€™t see yet how snapd can do this differently.

@robert.ancell Can you help @morphis here. He wants to open a link in the user browser running in the current user session from within the snapd process running as root.

@morphis is right here, by routing the request to open a URL through snapd you lose the ability to prompt the session to launch a browser. As stated above, there is no means for a process outside a session (e.g. snapd as root) can contact the session D-Bus for that session. For that to occur, you would need the external process to have some presence inside the session (like the snapd --user as @morphis suggested). This is how Polkit does it (with the polkit authentication agent contacting the Polkit system service). Donā€™t underestimate the risk of doing this though, it requires the root daemon to have a level of trust in this session process and ensure itā€™s not maliciously replaced.

@niemeyer See @robert.ancell reply from above. What is your call on this?

Iā€™ll need to do some research as itā€™d be great to avoid having another moving piece simply to open a URL. Weā€™ve been there.

So Iā€™ve bumped into an issue using xdg-open in a strictly confined snap of Rambox, which is an Electron app.

I am testing on Ubuntu 16.04 desktop and have snapd-xdg-open installed. If I exclude xdg-utils from the snap clicking URLs within Rambox does nothing. There is no output on stdout/stderr or in the logs. If I include xdg-utils in the snap clicking URLs generates the following on stdout:

Error org.freedesktop.DBus.Error.ServiceUnknown: The name com.canonical.SafeLauncher was not provided by any .service files
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: x-www-browser: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: firefox: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: iceweasel: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: seamonkey: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: mozilla: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: epiphany: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: konqueror: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: chromium-browser: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: google-chrome: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: www-browser: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: links2: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: elinks: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: links: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: lynx: not found
/snap/rambox-test/x6/usr/bin/xdg-open: 771: /snap/rambox-test/x6/usr/bin/xdg-open: w3m: not found
xdg-open: no method available for opening 'https://play.google.com/store/apps/details?id=com.google.android.apps.hangoutsdialer&referrer=utm_source%3Dlandingpage%26utm_campaign%3Dlandingpage&hl=en-GB'

Any bright ideas how to over come this?

yes, you should never include xdg-utils. the core snap currently ships its own xdg-open that will talk via dbus to the snapd-xdg-open service that sits in your user session. if you include xdg-utils in your snap this will override the binary inside the core snap (as you can see in the paths in your error) and send its url open requests nowhere.

is teh electron app actually shelling out to xdg-open or does it use electron.shell to spawn the external process ? note that electron.shell will definitely not work ā€¦

the pull reqest below has a working variant ā€¦

https://github.com/ryanleesipes/snapcraft-forum/pull/3

Thanks for the feedback. Looks like Rambox uses electron.shell:

so i fear you either need to patch it or you need to cheat with awful hacks ā€¦ (one way would be to add xdg-open to stage-packages, ship a script called ā€œx-www-browserā€ in your snap that takes the first arg as URL that then calls ā€œ/usr/local/bin/xdg-open $URLā€ (which is the one inside the core snap))

This is wrong. Donā€™t bundle xdg-open in your snap, that will never work. Just do nothing and assume it is there.

I know itā€™s wrong. I did it to try and surface errors :slight_smile: