XDG permissions stores should be configurable with snapd

The XDG portals store some persistent data in ~/.local/share/flatpak/db, examples of such data is the preferred program for opening MIME types with the OpenURI portal, files opened with the OpenFile portal, etc.

One common criticism I experience is that after selecting the same application 3 times successively, the OpenFile portal will stop asking for an application and simply pick what it considers default. The API does expose an always-ask flag, but this can’t be accessed by Core’s xdg-open (an extra parameter for this would be nice), and doesn’t provide the granualarity of control to the user that can be achieved by editing the stores directly.

The best solution I’ve found so far is to use flatpak to edit the databases, e.g:

flatpak permission-set --data "{'always-ask':<true>}" desktop-used-apps text/markdown snap.joplin-desktop org.gnome.gedit 0 3

It would be nice if snap had a way to do this itself without encouraging people to install Flatpak. It’d be even nicer if it could be incorporated in a way that’s more obvious about it, perhaps it’d be ideal inside snap-store next to the permissions tab for example.

Is there any better route right now than using Flatpak’s CLI to do the dirty work, or is there something obvious I’m missing here? I could look into whipping something up myself, but I thought I’d take bring it up in the forums first incase there’s some concensus on if/where this kind of feature belongs.

Background reading

1 Like

Is this an issue with the xdg-open implementation inside strict snaps which is implemented by snapctl user-open ... ? Relevant Go code for snapd is located at https://github.com/snapcore/snapd/blob/master/usersession/xdgopenproxy/xdgopenproxy.go, you might be able to add an option which is processed by https://github.com/snapcore/snapd/blob/master/cmd/snapctl/main.go and handed over to xdgopenproxy.Run(...)

Having taken a look at it now, /bin/xdg-open is fine, snapctl/main.go needs patching in order to not be hardcoded to demand exactly 3 arguments; and might require argument parsing.

To actually get the desired behaviour, https://github.com/snapcore/snapd/blob/9dfdb372b17d0225a6e8dff61631d4c44f70cc57/usersession/xdgopenproxy/portal_launcher.go#L151 also needs changing so that the variant is customisable, and tying it all together in a way that’s maintainable/correct so that there’s a way to get this from xdg-open to dbus without accidentally breaking someone.

This is my first attempt at Go (I believe it has no optional parameters? Which is unfortunate here :c) and snapd, so I’ll give it a go to get something usable but I’m not a professional so ;).

We can’t grant snaps access to xdg-permission-store, as it is explicitly there to store settings about sandboxed apps access to the system.

It does sound like passing ask=True in the options dictionary argument of the OpenURI.OpenFile D-Bus method would achieve what you’re after, which I guess is what you’re trying to do digging into the xdgopenproxy code.

One thing to keep in mind is that nothing the /usr/bin/xdg-open proxy provided by snapd does is privileged. There’s nothing stopping you from providing your own implementation in its place (in fact, apps using the GLib/GTK API will end up making the D-Bus call directly if they’ve enabled portal support). So if you find the Go code unfamiliar, you could always write something in another language and package that in your snap.

I’m not suggesting that any arbitrary snap needs access to the permissions store, only either snapd itself or something with suitable authority, e.g the snap-store snap for example could be a good candidate IMO, I wouldn’t see this as an escalation of privilege for the snap-store given it can already install any arbitrary classic app/snap.

But I can see that given I’m likely the first person to ask for it then it might not be something worth investigating properly just yet, but I thought I’d post the feedback anyway, it gets it stored on the forum and open to future people who might search for it and such.

I’ve spent some time on the"ask" as an option just now. 3 hours of which may have accidentally been recompiling the snapd snap but not successfully re-executing the binary. The practise is welcome :wink: I understand it could be done in another binary but I think there’s good value to be added by trying to get it into xdg-open.

Alongside the ask flag, there’s also the “writable” flag which might actually solve another problem I’m having that I’m looking into now. Specifically I’m hoping it might solve the scenario where one snap writes contents into its own $SNAP_USER_DATA, tries to portal it to another snap, and the recieving snap can’t actually open it because it’s blocked by the home interface, leading to negative synergy between snaps where it’s better off not having one of them as a snap at all. This has been popping up from users lately and it fits right in with --ask so I’ll hopefully have some news later.

Let us know if we can help make it easier to test snapd changes, after you have successfully rebuilt the snapd snap, you should be able to just snap install snapd_*.snap --dangerous and it will be used automatically provided you don’t also have a snapd deb that was hand-built as well with a newer version number

I’m unsure on what’s technically happened but my experience so far has been the following:

  • Downloaded the snapd source and run snapcraft in it, everything works as expected.
  • Went to work modifying some of the code mentioned above, tried to rerun the build without cleaning it
  • Snapcraft now fails reliably because this keeps rerunning snapcraftctl set-version and aborting.
  • I don’t want to cleanbuild everytime because without caching parts it’s unnecessarily slow, so I had to run find . -name snapcraft.yaml to find the file, because it’s in none of the places I’d usually look, and then swapped adopt-info to version: git, because I assume this is essentially what the script was doing anyway (and remove snapcraftctl set-version).

Now part two which explains how I spent 3 hours like a noob,

  • Installed my patched snapd snap, where I’d edited one line of code with a runtime error, being new to Go and all
  • Snapd re-exec’s it and the testing shows the code is broken (The version number changed)
  • Fix the code and rebuild the snap
  • The version tag on the snap is the same on the new revision
  • snapd claims to restart but doesn’t,
james@james-Virtual-Machine:~/snapd$ sudo snap install snapd_2.51.1+git768.9dfdb37-dirty_amd64.snap --dangerous
[sudo] password for james: 
2021-07-02T18:23:19+01:00 INFO Waiting for automatic snapd restart...
snapd 2.51.1+git768.9dfdb37-dirty installed

and I spend 3 hours in a loop of trying to fix this one line until realising that even upon reverting all changes to the master in Git and clean building, it’s still broken.

  • Resort to the reboot of last resort and realise what’s happened.

My assumption is that while snapd does re-exec, it’s only actually doing it when the version tag changes, not the revision, so I presume unless you’re actively making git commits prior to snapcraft, it’s misleading.

And I suppose this is all first day problems when using something you’re unfamiliar with, but hopefully the feedbacks helpful none the less.

Otherwise progress is good, although the xdg portals are lacking in documentation so there’s a lot of fiddling, but nothing out of the norm.