xdg-desktop-portal
xdg-desktop-portal copied to clipboard
open-uri: application URI handlers
Add support for applications to handle URIs more specifically than just by scheme.
If an application invokes OpenUri() with URI it claims to handle, the portal will omit it from the possible handlers and fallback to the browser if there are none.
This is being coordinated with the proposed intent-apps-spec, and an initial implementation in GLib:
This is a good start.
But I think we also need an additional handler for something requesting a specific app to open a deep link and if that app is not installed, prompt to install it.
There recently was a security "incident" in Germany, where an app was attacked, due to it only asking for a schema and somebody placed a malicious app, that basically got priority (as oder is not defined by the ios implementation it seems).
So the correct way to handle that would have been to use apples universal links https://developer.apple.com/ios/universal-links/
Here's a post about the vulnerability https://ctrlalt.medium.com/space-attack-spoofing-eids-password-authenticated-connection-establishment-11561e5657b1
I think it would also be good to support proper Regex in addition to the simple patterns that g_pattern_match_simple() supports (supported URLs can become complicated, e.g. a Spotify desktop application would only be able to support a very specific set of URLs like ^https://open.spotify.com/(artist|album|track)/[[:alnum:]]+\??.*$).
See for example android:pathPattern vs android:pathAdvancedPattern as prior art from the Android scheme matching implementation.
@razzeee
But I think we also need an additional handler for something requesting a specific app to open a deep link and if that app is not installed, prompt to install it.
How would a user implicitly request a specific app with the action of opening a URI? Would that make e.g. Freetube unable to open YouTube links if there were an official YouTube app?
Apple uses an apple-app-site-association file on the application's website, but that approach seems like a fairly big constraint for FOSS projects. This sort of metadata seems like it might be a good fit for AppStream, but then we'd have to rely on that being available and up to date.
@vimpostor
I think it would also be good to support proper Regex in addition to the simple patterns that g_pattern_match_simple() supports
I'm not sure that's a good idea, to be honest. Something like Android's pathAdvancedPattern might be possible, but Regex is far too vulnerable to DoS attacks.
Would https://open.spotify.com/*/* not work for Spotify, or are their paths under open.spotify.com/ that aren't for "opening"? I'm interested in examples of URIs that can't be matched with simple patterns, but we'd like to keep this relatively simple and safe, too.
but Regex is far too vulnerable to DoS attacks.
That sounds like a far fetched attack scenario. Regex is cheap enough that an attacker would need to busy-spin matching URLs anyway, so I don't think there is a difference between matching patterns and matching Regex in your scenario.
Would
https://open.spotify.com/*/*not work for Spotify, or are their paths underopen.spotify.com/that aren't for "opening"?
I am not entirely sure, but I know that the Spotify APK doesn't accept all paths under that domain, but rather has a few hardcoded prefixes. Note that it uses neither pathPattern nor pathAdvancedPattern, but a conjunction of pathPrefix.
In any case such a Regex feature could be still useful for a user who wants to configure what exactly opens up in the app, I don't think you need to be terribly creative to find usecases there.
That being said, I don't want to block this very useful PR with my remark, just wanted to put some eyes on the prior art that happened in Android land.
That sounds like a far fetched attack scenario. Regex is cheap enough that an attacker would need to busy-spin matching URLs anyway, so I don't think there is a difference between matching patterns and matching Regex in your scenario.
ReDoS attacks are relatively common, and likely why Android's pathPatternAdvanced is not Regex and explicitly doesn't support backtracking.
Note that it uses neither
pathPatternnorpathAdvancedPattern, but a conjunction ofpathPrefix.
Sorry, I'm not sure what you mean by conjunction here.
That being said, I don't want to block this very useful PR with my remark, just wanted to put some eyes on the prior art that happened in Android land.
Thanks! We've been looking at examples from other platforms, and it's most useful to have real-world examples of the URIs. I suspect most applications try to keep it simple, but more data points are always helpful.
Something not immediately obvious is that applications can "reject" URIs by invoking OpenUri(). To prevent re-entrancy a URI can't be directed to the application that opened it, so this may be an effective way to handle over-eager matching patterns like open.spotify.com/*.
@razzeee
But I think we also need an additional handler for something requesting a specific app to open a deep link and if that app is not installed, prompt to install it.
How would a user implicitly request a specific app with the action of opening a URI? Would that make e.g. Freetube unable to open YouTube links if there were an official YouTube app?
I think the idea would not be a user to do that, but an app shelling out to another app. Like a government app (a), trying to authenticate you via another specific app (b). So app a would somehow hard code the calls to app b, and it should never allow for app c (an attackers app) to handle that call.
App b could be something along the lines of this for e.g. https://flathub.org/apps/de.bund.ausweisapp.ausweisapp2
And yes, if the youtube app used "the wrong api" as in what I proposed here, it would lock it into the youtube app and freetube would be unable to open these.
Apple uses an
apple-app-site-associationfile on the application's website, but that approach seems like a fairly big constraint for FOSS projects. This sort of metadata seems like it might be a good fit for AppStream, but then we'd have to rely on that being available and up to date.
I actually haven't looked that deep, but it seemed pretty important to me, to cover both bases.
I think we can reasonably ignore regex for now. If the simple matching turns out to be insufficient we can revisit that part and make it more powerful. We just have to make sure the portal allows this forwards compatibility.
mime-types and URI handlers have the same security issue described by @razzeee. Android and iOS usually solve this kind of issue by putting up a file at a well-known path for URIs but we can't rely on that. We need a solution that works by putting some metadata in the flatpak manifest or desktop file and rely on reviews to make sure the permissions granted there are reasonable.
This MR already gets the "permissions" from the desktop file which should be reviewed by actual people.
I'm not sure if we need some mechanism to lock specific URIs to specific apps. If there is an alternative ausweisapp for example, it should still work. If an app which has no business handling this still exposes the handler, it should not pass review.
If there is an alternative ausweisapp for example, it should still work. If an app which has no business handling this still exposes the handler, it should not pass review.
I'm not convinced this would work in the real world. I guess we're saying, that only apps from flathub are safe then, as only those might be reviewed.
It would obviously be nice for an alternative ausweisapp to work, but it could also just be an app attacking/sniffing on the other app. And this would be possible, as soon as the user has some other repo added I think? As we're not forcing apps from flathub to only open apps from flathub for e.g.
We will have the same problem with webauthn/fido where an app should not be able to access any credentials but only ones scoped to itself or specific remotes (hosts basically). Again, iOS and Android solve this by having a file at a well-known location on the host but we won't be able to get e.g. google to add random gnome apps to that file. We'll again have to use the flatpak manifest or the desktop file to make the association and let reviewers check if it is reasonable.
I'm also not sure how "pinning" a specific app would be useful. Why can't an "evil" app not pin itself?
I'm also not sure how "pinning" a specific app would be useful. Why can't an "evil" app not pin itself?
Because it's pinned in the other app calling it. Without control of the other app, the "evil" app can't change that. (at least that's what I hope and what iOS seems to rely upon)
Okay, but how does the calling app know which is not the evil app? The calling app must understand both the URL and that one specific app that should then be called. Could as well just call the app directly instead of going through portals (not right now because dbus limitations, but it should become possible).
Yeah, it probably needs both to lock it in, so rdns and repo/origin.
I have no idea about the implementation details when it comes to dbus, I just feel strongly that we need both for a versatile / safe platform.