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

open-uri: application URI handlers

Open andyholmes opened this issue 1 year ago • 14 comments

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:

andyholmes avatar Mar 22 '24 18:03 andyholmes

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

razzeee avatar May 10 '24 22:05 razzeee

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.

vimpostor avatar May 19 '24 14:05 vimpostor

@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.

andyholmes avatar May 19 '24 16:05 andyholmes

@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.

andyholmes avatar May 19 '24 17:05 andyholmes

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 under open.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.

vimpostor avatar May 19 '24 17:05 vimpostor

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 pathPattern nor pathAdvancedPattern, but a conjunction of pathPrefix.

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/*.

andyholmes avatar May 19 '24 20:05 andyholmes

@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-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.

I actually haven't looked that deep, but it seemed pretty important to me, to cover both bases.

razzeee avatar May 21 '24 21:05 razzeee

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.

swick avatar May 22 '24 11:05 swick

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.

swick avatar May 22 '24 12:05 swick

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.

razzeee avatar May 22 '24 12:05 razzeee

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?

swick avatar May 22 '24 13:05 swick

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)

razzeee avatar May 22 '24 14:05 razzeee

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).

swick avatar May 22 '24 15:05 swick

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.

razzeee avatar May 22 '24 17:05 razzeee