github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/usersession/userd/launcher_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2017 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package userd_test 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "syscall" 27 "testing" 28 29 "github.com/godbus/dbus" 30 . "gopkg.in/check.v1" 31 32 "github.com/snapcore/snapd/osutil/sys" 33 "github.com/snapcore/snapd/release" 34 "github.com/snapcore/snapd/testutil" 35 "github.com/snapcore/snapd/usersession/userd" 36 ) 37 38 func Test(t *testing.T) { TestingT(t) } 39 40 type launcherSuite struct { 41 testutil.BaseTest 42 43 launcher *userd.Launcher 44 mockXdgOpen *testutil.MockCmd 45 } 46 47 var _ = Suite(&launcherSuite{}) 48 49 func (s *launcherSuite) SetUpTest(c *C) { 50 s.BaseTest.SetUpTest(c) 51 52 s.AddCleanup(release.MockOnClassic(true)) 53 s.launcher = &userd.Launcher{} 54 s.mockXdgOpen = testutil.MockCommand(c, "xdg-open", "") 55 s.AddCleanup(s.mockXdgOpen.Restore) 56 s.AddCleanup(userd.MockSnapFromSender(func(*dbus.Conn, dbus.Sender) (string, error) { 57 return "some-snap", nil 58 })) 59 } 60 61 func (s *launcherSuite) TestOpenURLWithNotAllowedScheme(c *C) { 62 for _, t := range []struct { 63 url string 64 errMatcher string 65 }{ 66 {"tel://049112233445566", "Supplied URL scheme \"tel\" is not allowed"}, 67 {"aabbccdd0011", "Supplied URL scheme \"\" is not allowed"}, 68 {"invälid:%url", dbus.ErrMsgInvalidArg.Error()}, 69 } { 70 err := s.launcher.OpenURL(t.url, ":some-dbus-sender") 71 c.Assert(err, ErrorMatches, t.errMatcher) 72 c.Assert(s.mockXdgOpen.Calls(), IsNil) 73 } 74 } 75 76 func (s *launcherSuite) TestOpenURLWithAllowedSchemeHappy(c *C) { 77 for _, schema := range []string{"http", "https", "mailto", "snap", "help", "apt", "zoommtg", "zoomus", "zoomphonecall", "slack", "msteams"} { 78 err := s.launcher.OpenURL(schema+"://snapcraft.io", ":some-dbus-sender") 79 c.Assert(err, IsNil) 80 c.Assert(s.mockXdgOpen.Calls(), DeepEquals, [][]string{ 81 {"xdg-open", schema + "://snapcraft.io"}, 82 }) 83 s.mockXdgOpen.ForgetCalls() 84 } 85 } 86 87 func (s *launcherSuite) TestOpenURLWithFailingXdgOpen(c *C) { 88 cmd := testutil.MockCommand(c, "xdg-open", "false") 89 defer cmd.Restore() 90 91 err := s.launcher.OpenURL("https://snapcraft.io", ":some-dbus-sender") 92 c.Assert(err, NotNil) 93 c.Assert(err, ErrorMatches, "cannot open supplied URL") 94 } 95 96 func mockUICommands(c *C, script string) (restore func()) { 97 mock := testutil.MockCommand(c, "zenity", script) 98 mock.Also("kdialog", script) 99 100 return func() { 101 mock.Restore() 102 } 103 } 104 105 func (s *launcherSuite) TestOpenFileUserAccepts(c *C) { 106 restore := mockUICommands(c, "true") 107 defer restore() 108 109 path := filepath.Join(c.MkDir(), "test.txt") 110 c.Assert(ioutil.WriteFile(path, []byte("Hello world"), 0644), IsNil) 111 112 file, err := os.Open(path) 113 c.Assert(err, IsNil) 114 defer file.Close() 115 116 dupFd, err := syscall.Dup(int(file.Fd())) 117 c.Assert(err, IsNil) 118 119 err = s.launcher.OpenFile("", dbus.UnixFD(dupFd), ":some-dbus-sender") 120 c.Assert(err, IsNil) 121 c.Assert(s.mockXdgOpen.Calls(), DeepEquals, [][]string{ 122 {"xdg-open", path}, 123 }) 124 } 125 126 func (s *launcherSuite) TestOpenFileUserDeclines(c *C) { 127 restore := mockUICommands(c, "false") 128 defer restore() 129 130 path := filepath.Join(c.MkDir(), "test.txt") 131 c.Assert(ioutil.WriteFile(path, []byte("Hello world"), 0644), IsNil) 132 133 file, err := os.Open(path) 134 c.Assert(err, IsNil) 135 defer file.Close() 136 137 dupFd, err := syscall.Dup(int(file.Fd())) 138 c.Assert(err, IsNil) 139 140 err = s.launcher.OpenFile("", dbus.UnixFD(dupFd), ":some-dbus-sender") 141 c.Assert(err, NotNil) 142 c.Assert(err, ErrorMatches, "permission denied") 143 c.Assert(s.mockXdgOpen.Calls(), IsNil) 144 } 145 146 func (s *launcherSuite) TestOpenFileSucceedsWithDirectory(c *C) { 147 restore := mockUICommands(c, "true") 148 defer restore() 149 150 dir := c.MkDir() 151 fd, err := syscall.Open(dir, syscall.O_RDONLY|syscall.O_DIRECTORY, 0755) 152 c.Assert(err, IsNil) 153 defer syscall.Close(fd) 154 155 dupFd, err := syscall.Dup(fd) 156 c.Assert(err, IsNil) 157 158 err = s.launcher.OpenFile("", dbus.UnixFD(dupFd), ":some-dbus-sender") 159 c.Assert(err, IsNil) 160 c.Assert(s.mockXdgOpen.Calls(), DeepEquals, [][]string{ 161 {"xdg-open", dir}, 162 }) 163 } 164 165 func (s *launcherSuite) TestOpenFileFailsWithDeviceFile(c *C) { 166 restore := mockUICommands(c, "true") 167 defer restore() 168 169 file, err := os.Open("/dev/null") 170 c.Assert(err, IsNil) 171 defer file.Close() 172 173 dupFd, err := syscall.Dup(int(file.Fd())) 174 c.Assert(err, IsNil) 175 176 err = s.launcher.OpenFile("", dbus.UnixFD(dupFd), ":some-dbus-sender") 177 c.Assert(err, NotNil) 178 c.Assert(err, ErrorMatches, "cannot open anything other than regular files or directories") 179 c.Assert(s.mockXdgOpen.Calls(), IsNil) 180 } 181 182 func (s *launcherSuite) TestOpenFileFailsWithPathDescriptor(c *C) { 183 restore := mockUICommands(c, "true") 184 defer restore() 185 186 dir := c.MkDir() 187 fd, err := syscall.Open(dir, sys.O_PATH, 0755) 188 c.Assert(err, IsNil) 189 defer syscall.Close(fd) 190 191 dupFd, err := syscall.Dup(fd) 192 c.Assert(err, IsNil) 193 194 err = s.launcher.OpenFile("", dbus.UnixFD(dupFd), ":some-dbus-sender") 195 c.Assert(err, NotNil) 196 c.Assert(err, ErrorMatches, "cannot use file descriptors opened using O_PATH") 197 c.Assert(s.mockXdgOpen.Calls(), IsNil) 198 } 199 200 func (s *launcherSuite) TestFailsOnUbuntuCore(c *C) { 201 restore := release.MockOnClassic(false) 202 defer restore() 203 204 path := filepath.Join(c.MkDir(), "test.txt") 205 c.Assert(ioutil.WriteFile(path, []byte("Hello world"), 0644), IsNil) 206 file, err := os.Open(path) 207 c.Assert(err, IsNil) 208 defer file.Close() 209 dupFd, err := syscall.Dup(int(file.Fd())) 210 c.Assert(err, IsNil) 211 212 err = s.launcher.OpenFile("", dbus.UnixFD(dupFd), ":some-dbus-sender") 213 c.Check(err, ErrorMatches, "not supported on Ubuntu Core") 214 215 err = s.launcher.OpenURL("https://snapcraft.io", ":some-dbus-sender") 216 c.Check(err, ErrorMatches, "not supported on Ubuntu Core") 217 218 c.Check(s.mockXdgOpen.Calls(), HasLen, 0) 219 }