New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
usersession/userd: query xdg-mime to check for fallback handlers of a given scheme #11200
usersession/userd: query xdg-mime to check for fallback handlers of a given scheme #11200
Conversation
… given scheme Most of the handling is of xdg-open requests from the snaps id done by xdg-desktop-protal now, the handler in userd remains a fallback for scenarios where the desktop setup is incomplete. The code of io.snapcraft.OpenURL() handler would only allow a handful of schemes to be passed to xdg-open on the host side. However, updating the list of schemes manually has proven be to unmaintainable, and got filled with various vendor specific entries. In snapcore#7731 (comment) an approach was proposed to use xdg-query to find out whether there is handler for given scheme on the host side, and if so allow the URL to be passed to xdg-open, which is implemented in this patch. Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a couple little nitpicks but overall looks great to me, I do think we need a security review on this however
usersession/userd/launcher.go
Outdated
// OpenURL implements the 'OpenURL' method of the 'io.snapcraft.Launcher' | ||
// DBus interface. Before the provided url is passed to xdg-open the scheme is | ||
// validated against a list of allowed schemes. All other schemes are denied. | ||
func (s *Launcher) OpenURL(addr string, sender dbus.Sender) *dbus.Error { | ||
logger.Noticef("open url: %q", addr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be a Noticef? Or a Debugf?
usersession/userd/launcher.go
Outdated
if err != nil { | ||
logger.Noticef("cannot obtain scheme handler for %q: %v", u.Scheme, err) | ||
} | ||
isAllowed = isAllowed || has |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we know isAllowed
is false in this branch, we could just do
isAllowed = isAllowed || has | |
isAllowed = has |
usersession/userd/launcher_test.go
Outdated
c.Assert(err, NotNil) | ||
c.Assert(err, ErrorMatches, `Supplied URL scheme "fallback-scheme" is not allowed`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c.Assert(err, NotNil) | |
c.Assert(err, ErrorMatches, `Supplied URL scheme "fallback-scheme" is not allowed`) | |
c.Assert(err, ErrorMatches, `Supplied URL scheme "fallback-scheme" is not allowed`) |
@@ -153,10 +157,26 @@ func checkOnClassic() *dbus.Error { | |||
return nil | |||
} | |||
|
|||
// see https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#file-naming | |||
var validDesktopFileName = regexp.MustCompile(`^[A-Za-z-_][A-Za-z0-9-_]*(\.[A-Za-z-_][A-Za-z0-9-_]*)*\.desktop$`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spot checked a few cases and this looks correct to me
@@ -26,6 +26,27 @@ prepare: | | |||
/ \ | |||
org.freedesktop.DBus.Peer.Ping | |||
|
|||
# setup the handler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the spread test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…-check-local-providers
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Codecov Report
@@ Coverage Diff @@
## master #11200 +/- ##
=======================================
Coverage 78.26% 78.26%
=======================================
Files 930 930
Lines 106315 106340 +25
=======================================
+ Hits 83210 83231 +21
- Misses 17936 17939 +3
- Partials 5169 5170 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a nitpick :-)
|
||
func schemeHasHandler(scheme string) (bool, error) { | ||
cmd := exec.Command("xdg-mime", "query", "default", "x-scheme-handler/"+scheme) | ||
out, err := cmd.CombinedOutput() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: it would be more robust to use just Output()
here, in case the xdg-mime
program emits some warning on the stderr (or even just some debugging message). For example if the combined output was this:
Warning: myapp.desktop: invalid desktop file [<- stderr]
gimp.desktop [<- stdout]
the current implementation of this function would return false
, whereas ideally it should return true
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a TODO here to consider using Output. TBH despite my attempts I was not able to make xdg-mime log anything to stderr even whe ~/.config/mimeapps.list was clearly malformed or missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL parsing in Go looks pretty safe - so it doesn't appear a URL could try and inject shell content or similar via the URI scheme - plus exec.Command()
doesn't execute a shell either so even if a user could somehow inject extra content, it won't get executed when we go and run xdg-mime
. Finally, if a user has installed an application then I don't see a reason not to honor that which this implementation allows.
So from a security (and usability) point of view, this looks great.
Thanks.
…me support Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
…-check-local-providers
Looking at xdg-desktop-portal, it will skip prompting the user before launching the URI if:
The proposed behaviour here is not identical (i.e. it's going to differ if there are multiple providers available for a scheme), but seems reasonable. While snaps can modify mime default handlers via userd, it does result in a zenity dialog prompt. If there was a security problem, I'd tend to think that end would be the problem. |
@mvo5 this is ready to land, can you merge the branch please? |
PR snapcore#11200 added a way to query for a handler for any given URL scheme. Extend this and ask the user whether a URL should be opened by a given handler. This is similar to what the desktop portal does, but instead of presenting the app chooser dialog, we only present the user with a yes/no question and the default handler. Note, that the implementation is only for the fallback io.snapcraft.Launcher handler, which would be called only if the desktop portal is not available. Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Most of the handling is of xdg-open requests from the snaps is done by
xdg-desktop-portal now, the handler in userd remains a fallback for scenarios
where the desktop setup is incomplete. The code of io.snapcraft.OpenURL()
handler would only allow a handful of schemes to be passed to xdg-open on the
host side. However, updating the list of schemes manually has proven be to
unmaintainable, and got filled with various vendor specific entries.
In #7731 (comment) an
approach was proposed to use xdg-query to find out whether there is handler for
given scheme on the host side, and if so allow the URL to be passed to xdg-open,
which is implemented in this patch.