xdg-desktop-portal icon indicating copy to clipboard operation
xdg-desktop-portal copied to clipboard

Allow a flatpak to discover/call another flatpak

Open Jehan opened this issue 7 years ago • 35 comments

Hi!

GIMP has this nifty new feature for opening RAW images, which is we use third-party advanced RAW software for the job. The idea is: why bother reimplementing a shitty 3-slider RAW developer as a plugin which will mostly be a toy when there are really good complete ones, and several being Free Software, like darktable or rawtherapee. So now when someone tries to open a RAW in GIMP, we detect installed darktable and rawtherapee and redirect the call to the user's favorite RAW software (if both are installed, one can choose one's favorite in GIMP's preferences). When the editing stops on this third-party software, it automatically sends back the result to GIMP for further editing.

Unfortunately this feature stopped working with flatpak. Flatpaked GIMP don't see DT/RT installed by the system packaging, nor installed as flatpak.

Let's say we don't mind not detecting non-flatpak DT/RT. After all, flatpak is a sandbox and one of the goal is to shield the system. But couldn't there be an API to detect other flatpaks and being able to run them? I see there is a darktable flatpak for instance. It would be awesome if we could detect it within GIMP flatpak and run org.darktable.Darktable.

Jehan avatar Dec 07 '17 01:12 Jehan

You can open URIs but it doesn't work for local file://'s so that is probably the best way to expose that. It does create an easy sandbox escape but the user will have to explicitly allow it.. don't know if that makes it ok.

TingPing avatar Dec 07 '17 01:12 TingPing

How would it work exactly? I'm not sure I understand your workaround.

For info, right now (out of flatpak), we discover the third-party app in a Linux OS by simply checking its availability in the path.

Jehan avatar Dec 07 '17 01:12 Jehan

You let the host handle file associations and you would just pass it the raw file.

TingPing avatar Dec 07 '17 02:12 TingPing

Not all RAW software will work well with GIMP (currently only darktable and rawtherapee). There is a coded layer between GIMP and the RAW software. This specific feature has been closely created together by developers of all 3 projects (GIMP, darktable and RawTherapee) so that there is a back-and-forth interaction/connection.

In particular if we just let file association handle the file, once the user is done developing the RAW, the third party software would not give back the result to GIMP. And that also means we can't just give the file to the RAW software in a common way. GIMP actually runs a command with specific options. Here is the workflow currently:

  • the photographer opens a RAW file in GIMP;
  • GIMP automatically opens the RAW file in DT/RT;
  • the photographer tweaks/develops the image in DT/RT;
  • when finished, the photographer closes DT/RT (no need to save/export anything);
  • GIMP automatically loads the result of the developed RAW;
  • the photographer can continue working on the image in GIMP.

So no, we can't just let the host handle file association. The point is not to redirect the file towards some other software and not hear about it anymore. That feature would make no sense at all (if that's what we want to do, we'd just say we don't support RAW images). The point is acknowledging that the RAW development is better done in a specialized software, but further image editing are better done in GIMP. This is basically a workflow where various more specialized software work together seamlessly and are connected, sharing images and work-in-progress at different steps, like a "Free Software graphics suite" or something.

Jehan avatar Dec 07 '17 02:12 Jehan

Well, thats just not how sandboxes work: they isolate applications from each other and from the host system. If you want deep integration, you can ship the auxiliary software as part of your flatpak, and have it run in the same sandbox. Otherwise, you may need an api between the two apps to facilitate this sort of interaction. A d-bus api would be much easier to integrate in the existing tooling than launching the app with special options.

matthiasclasen avatar Dec 07 '17 18:12 matthiasclasen

Ok we'll discuss this. It may indeed be better than a flatpak-specific communication protocol. I opened this on our side: https://bugzilla.gnome.org/show_bug.cgi?id=791362

Jehan avatar Dec 07 '17 19:12 Jehan

This is basically a portal question, so moving it over to xdg-desktop-portal

matthiasclasen avatar Dec 31 '18 14:12 matthiasclasen

Given an application-specific D-Bus API, and --talk-name=com.example.Foo in the app which needs to be able to tell Foo to do things, that app can tell whether Foo is installed by either trying to call a method on it (which would fail if it's not installed) or calling ListActivatableNames on org.freedesktop.DBus (the bus daemon itself, not the portal) to see whether it's present. The other half of this would be a “please install this app” portal.


The status quo is that, if you don't mind being GNOME specific and your app can talk to org.gnome.Software, you can tell it to show the details page for an app:

org.gtk.Actions.Activate("details", [GLib.Variant("(ss)", ("system/flatpak/flathub/desktop/org.gnome.dfeet/stable", ""))], {})

Or to install it (without user confirmation):

Activate("install", [GLib.Variant("(su)", ("system/flatpak/flathub/desktop/org.wesnoth.Wesnoth/stable", 1))], {})

Aside from the GNOME-specificity, there are some big caveats:

  • You have to know the remote name and branch name for the app
  • You can't tell when the app has been installed (or cancelled) without polling

I imagine that a better interaction would be (on GNOME):

  • App calls InstallApp(window_id, "com.example.Foo", {"preferred-remote": "org.flathub.Stable"})
  • If Foo is not installed:
    • User gets a cut-down version of the GNOME Software details page as a dialog, where they can choose to install Foo or cancel
    • Once they do one or the other, Response fires
  • If Foo is already installed:
    • Response fires at once? Unfortunately, this would allow any application to test for what other applications are installed, which has been deemed undesirable in the past, though at least the user would be spammed with dialogs for each app that's not installed so it would be visible…
  • Assuming success, App can now activate and talk to Foo over D-Bus

Seem plausible? @manuq can you comment from the point of view of wanting an API like this?

One thought was whether we could instead add a hint to OpenURI / OpenFile of the preferred application to use to open something, and in the case where that app is not installed, the portal could offer to install it.

wjt avatar Sep 03 '19 11:09 wjt

@wjt yes, your description matches exactly what an ideal portal API would look like.

  • Ability to check if another app is installed from a flatpaked app.
  • Ability to offer the user to install the app if not installed (through gnome-software in GNOME).
  • Continue the original app flow once the other app is installed.

And I agree, making this a user-facing portal mitigates the sandbox flaw of discovering other apps.

Regarding app A start talking to app B, our use-case only needs app B installed. We talk to gnome-shell to launch the other app with the org.gnome.Shell.AppLauncher.Launch() DBus method, and if that doesn't work we try org.gtk.Application.Activate().

manuq avatar Sep 03 '19 14:09 manuq

I think sneaking this into OpenURI might not work for all cases - you might not have a uri / file to open with the app, but instead a D-Bus request to make, or sth.

The overall plan sounds good to me.

If we are concerned about discovering installed apps, we could add a separate permission for that.

matthiasclasen avatar Sep 03 '19 18:09 matthiasclasen

One thing that I'm really not sure about is how you'd solve that original workflow without either questions that the user can't answer naturally, or a lack of question that would mean that too much is opened.

What would the UI look like for those apps? How do you trigger those links/API calls between applications?

From afar, it looks like a souped-up "OpenURI" with a signal back when editing is done, an "Edit In..." call, something which Android's Intent can already do.

Should this be part of a wider "Sharing" mechanism between apps instead? Or do we really want to poke holes just between those applications and no others?

hadess avatar Sep 03 '19 19:09 hadess

Or do we really want to poke holes just between those applications and no others?

On that, applications from the same domain on iOS have more open permissions between themselves, so that Google's YouTube application can offer to open a location in Google's Maps application rather than in the native/default maps application. I don't know if there's a mechanism to do that for arbitrary applications though.

hadess avatar Sep 03 '19 19:09 hadess

Or do we really want to poke holes just between those applications and no others?

On that, applications from the same domain on iOS have more open permissions between themselves, so that Google's YouTube application can offer to open a location in Google's Maps application rather than in the native/default maps application. I don't know if there's a mechanism to do that for arbitrary applications though.

It looks like Universal Links allows one iOS app to open another by attempting to opening a URL. A special file on the web server is checked at the time the target app is installed to determine whether it allows other apps to make it open a given URL.

Notably, if the app is not installed, attempting to open a supported URL will open the URL in Safari; it won't take the user to the app's detail page in the App Store. The rationale is the user always gets an immediate, meaningful view of the resource without being prompted to install the app. But the website can have a clear "install the companion app for a better experience" link.

The Android approach is more flexible and respectful of the user's wishes though, so it seems like a better model for us. Eg, if there's an OpenStreetMap-based app that claims to support URLs like "https://maps.google.com/*", the user can set the default handler. My understanding is, on iOS, only the controller of maps.google.com is allowed to determine which (at most one) app is allowed to handle each URL regex starting with its domain.

treitter avatar Nov 05 '19 22:11 treitter

Though I guess the original topic is best supported by a custom URI. The specific apps that support it could register as supporting that scheme and the calling app won't have to hard-code their names or URL structures. Opening a generic URI is a bit different than a service-specific URL though and only the former is appropriate for passing arbitrary local data.

Sorry if the last comment was a bit of a divergence :)

treitter avatar Nov 05 '19 22:11 treitter

https://lists.freedesktop.org/archives/xdg/2014-January/013068.html - Problem 3 here is somewhat relevant.

mrmcq2u avatar Nov 15 '19 19:11 mrmcq2u

I see 3 use cases:

  1. Actually communication between apps via dbus or some other ipc.
  2. Basically a safer version of flatpak-spawn flatpak run
  3. Share a file/socket between 2 app (The orginal question).

Number 2 is needed for browser native messaging host system like firefox's. It could also allow run extensions that just provide binary run with another set of permissions. Inkscape has a cli and sandboxed latex will help alot.

marcthe12 avatar May 07 '20 15:05 marcthe12

Just piling onto the discussion here. Other cross-flatpak dependencies (already packaged) are that the OpenShot app leverages both Blender and Inkscape.

One of the nice things about Flatpak is that the packaged apps don't need to be flatpak aware. Seems like many of the suggestions fundamentally want to change how programs are executed under linux. If an app has a preferences dialog to specify the path to another executable, why shouldn't I be allowed to type "flatpak run my.app.Here app " from within a sandbox? Or make a script in $HOME/bin that does the same? Seems like the choices are: flatpak adapts to apps as they are written, or it forces all app writers to add "flatpak support".

The simple solution, of course, is to build flatpaks with combinations of apps. Need access to another app? Bundle it. This also gives the package maintainer control over the version bundled.

bnordgren avatar Nov 28 '20 17:11 bnordgren

I think no adaption is required, you just need some patches to have – as you said – some script in a bin dir that then executes the flatpak run command. Patches, to make applications work better in flatpaks, are already used in many apps today on Flathub e.g., so this is not a problem IMHO.

rugk avatar Nov 28 '20 17:11 rugk

I don't believe you can currently call flatpak from within flatpak. Check out the following and tell me what I'm missing:

[bnordgren@mine Title]$ flatpak ps
Instance   PID    Application           Runtime
2257365655 327395 org.openshot.OpenShot org.kde.Platform
[bnordgren@mine Title]$ flatpak enter 2257365655 bash
[📦 org.openshot.OpenShot ~]$ flatpak ps
bash: flatpak: command not found

Need to have a command that runs before you can point an app to the command you want to run.

bnordgren avatar Nov 28 '20 18:11 bnordgren

No you cannot, but if this was implemented, the application inside the flatpak would not need to be adjusted, you would likely only need to put in some wrapper scripts for the used binaries.

rugk avatar Nov 28 '20 19:11 rugk

Lets raise this to flatpak to handle fine grained permission to flatpak(for all flapak commands, usefull fo flatseal software centre and this case) and also permission to expose ipc stored in $XDG_RUNTIME/app.

marcthe12 avatar Nov 29 '20 05:11 marcthe12

Randomly casting about the internet, I learned about flatpak-spawn, which in line with my example up above should work like:

[bnordgren@mine]$ flatpak run --command=bash org.openshot.OpenShot
[📦 org.openshot.OpenShot]$ flatpak-spawn --host flatpak run org.blender.Blender
Read prefs: /home/bnordgren/.var/app/org.blender.Blender/config/blender/2.91/config/userpref.blend
/run/user/1000/gvfs/ non-existent directory
found bundled python: /app/blender/2.91/python
DEBUG:BlenderGIS-master.core.checkdeps:GDAL Python binding unavailable
DEBUG:BlenderGIS-master.core.checkdeps:PyProj unavailable
DEBUG:BlenderGIS-master.core.checkdeps:Pillow unavailable
DEBUG:BlenderGIS-master.core.checkdeps:ImageIO Freeimage plugin available

That opened the standard blender gui. Tweak the command line to put in the required command line arguments, and viola. From the man page (guess it still pays to RTFM):

       Unlike other flatpak commands, flatpak-spawn is available to applications inside the sandbox. It runs COMMAND outside the sandbox, either in another sandbox, or
       on the host.

       flatpak-spawn uses the Flatpak portal to create a copy the sandbox it was called from, optionally using tighter permissions and the latest version of the app and
       runtime.

bnordgren avatar Dec 28 '20 18:12 bnordgren

@bnordgren That looks interesting, though I can't seem to get it to work myself. With --host I get the error Portal call failed: org.freedesktop.DBus.Error.ServiceUnknown. I also tried with --sandbox but with that I get bwrap: execvp flatpak: No such file or directory. Does using this require a special permission?

Taiko2k avatar Dec 29 '20 00:12 Taiko2k

Not that I know of. I just did that as a regular user on fedora 33 silverblue. My user account is in sudo/wheel, as it's the only non-root account on the system, but I didn't actually use any elevated privileges as far as I know. I'm what you might call a remedial flatpak user, not an expert. Others may have more insight.

bnordgren avatar Dec 29 '20 19:12 bnordgren

@Taiko2k flatpak-spawn's man page literally mentions you need to provide D-Bus access to org.freedesktop.Flatpak, granted this unto itself probably barely makes any sense to anyone unfamiliar with D-Bus and talk permissions in Flatpak.

Depending on the Flatpak you're trying to flatpak-spawn from you may already have talk access to that interface. That's probably why yours and @bnordgren's results differed.

Try testing flatpak-spawn from any sandbox using the following: flatpak run --talk-name=org.freedesktop.Flatpak --command=sh com.flatpak.Choice.

You may then make the changes permanent by registering the permission with flatpak-override. Hope this helps.

kon14 avatar Dec 29 '20 20:12 kon14

@kon14 Just out of curiosity, it looks to me that once these talk permissions are established, flatpak-spawn essentially acts like a get out of jail free card for any process in the sandbox. While useful in this case, it sure seems that this defeats at least the process-containment aspect of a sandbox. Is this accurate, or are there other controls which would prevent me from running arbitrary commands on the host (like sudo rm -rf /*) from within the sandbox?

bnordgren avatar Dec 31 '20 16:12 bnordgren

We definitely need fine grain permissions on flatpak-spawn. maybe we should have a sandbox flatpak command in a flatpak. flatpak-spawn flatpak override is a security time bomb. most people just need flatpak run or a few host commands. May be take queques from polkit

marcthe12 avatar Jan 01 '21 05:01 marcthe12

Just wanted to bring up my browser integration use-case and the associated pain-points..


I have installed org.mozilla.firefox (for DRM stuff) and com.microsoft.Teams on Alpine Linux desktop (as google's DRM plugin windivine and msteams are proprietary software with no musl binaries .. obviously).

I received an email with invitation link to a Teams meeting.

If I click on the link in sandboxed friefox, the page it redirects to has an iframe with src value that looks like msteams:/l/meetup-join/19.... (long string). The page itself prompts to open msteam but naturally it is not discoverable in firefox sandbox.

Insult to the injury, there is currently no way to sign in using an invitation link in their desktop app..

So my workaround is to HTML decode that src value with quotes "msteams:/l/meetup...." and launch teams from suckless terminal:

$ flatpak run \
    --env=DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbusLcsUc61GBB,guid=c1005d826f37b49af839644f60bc4df0' \
    -vvv com.microsoft.Teams "msteams:/l/meetup-join....."
    
# that --env thingy is yet another workaround for https://github.com/flathub/com.microsoft.Teams/issues/61

kasperk81 avatar Jun 10 '21 19:06 kasperk81

what an ideal portal API would look like.

  • Ability to check if another app is installed from a flatpaked app.

There may be a fingerprinting risk here if flatpak apps can identify what other applications are installed on your system

It may be slightly better if they can only tell which protocols / message-types are handled and not exactly which apps are handling them?

An alternative with a worse UX could be to completely disallow any introspection of other protocols/apps, with the suggestion that every app that needs to call out to another one should blindly attempt it and also display instructions on-screen for users to install a recommended app if nothing happens (or, instead of instructions, a flatpak-managed button that streamlines the installation)?

Behavioural advertising has really ruined things for everyone here, and now we need to consider ways to block cross-app tracking :S

jokeyrhyme avatar Jun 10 '21 20:06 jokeyrhyme

@kasperk81

I have installed org.mozilla.firefox (for DRM stuff) and com.microsoft.Teams on Alpine Linux desktop (as google's DRM plugin windivine and msteams are proprietary software with no musl binaries .. obviously).

I have a similar setup with Firefox, Discord, Slack, Zoom, and a whole bunch of similar apps all installed via flatpak, and I am able to click links in Firefox that result in being handled over in the Slack and other flatpak apps just fine

So, I believe the issue you've encountered is specific to Microsoft Teams and should be reported to them?

The issue, however, is still a good example of how easy it is for app developers to improperly register protocol handlers, etc, so maybe there's a documentation or other outreach fix that can be done here?

jokeyrhyme avatar Jun 10 '21 20:06 jokeyrhyme