blob: 274537fc827169eb959fca41beb4164f4c61b747 [file] [log] [blame]
[email protected]8806d3b2012-04-13 06:46:341// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b96aa932009-08-12 21:34:492// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/shell_integration.h"
6
[email protected]07753f0f2013-02-05 07:52:597#include <cstdlib>
[email protected]af71d642010-03-12 10:29:048#include <map>
9
[email protected]14fbaed2013-05-02 07:54:0210#include "base/base_paths.h"
[email protected]af71d642010-03-12 10:29:0411#include "base/file_util.h"
[email protected]57999812013-02-24 05:40:5212#include "base/files/file_path.h"
[email protected]ea1a3f62012-11-16 20:34:2313#include "base/files/scoped_temp_dir.h"
[email protected]af71d642010-03-12 10:29:0414#include "base/message_loop.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]b96aa932009-08-12 21:34:4916#include "base/string_util.h"
[email protected]14fbaed2013-05-02 07:54:0217#include "base/test/scoped_path_override.h"
[email protected]be1ce6a72010-08-03 14:35:2218#include "base/utf_string_conversions.h"
[email protected]a0b60cfd2011-04-06 18:02:4119#include "chrome/browser/web_applications/web_app.h"
[email protected]42896802009-08-28 23:39:4420#include "chrome/common/chrome_constants.h"
[email protected]e97882f2012-06-04 02:23:1721#include "content/public/test/test_browser_thread.h"
[email protected]b96aa932009-08-12 21:34:4922#include "googleurl/src/gurl.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
[email protected]8ea8f1ef2013-01-06 18:39:0325#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]76b90d312010-08-03 03:00:5026#include "base/environment.h"
[email protected]98566d7a2012-04-17 00:28:5627#include "chrome/browser/shell_integration_linux.h"
[email protected]1fd5302c2011-05-28 04:06:4328#endif
[email protected]3bc60432010-03-12 11:15:1329
[email protected]b96aa932009-08-12 21:34:4930#define FPL FILE_PATH_LITERAL
31
[email protected]631bb742011-11-02 11:29:3932using content::BrowserThread;
33
[email protected]1fd5302c2011-05-28 04:06:4334#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]af71d642010-03-12 10:29:0435namespace {
36
37// Provides mock environment variables values based on a stored map.
[email protected]76b90d312010-08-03 03:00:5038class MockEnvironment : public base::Environment {
[email protected]af71d642010-03-12 10:29:0439 public:
[email protected]76b90d312010-08-03 03:00:5040 MockEnvironment() {}
[email protected]af71d642010-03-12 10:29:0441
42 void Set(const std::string& name, const std::string& value) {
43 variables_[name] = value;
44 }
45
[email protected]b94584a2013-02-07 03:02:0846 virtual bool GetVar(const char* variable_name, std::string* result) OVERRIDE {
[email protected]af71d642010-03-12 10:29:0447 if (ContainsKey(variables_, variable_name)) {
48 *result = variables_[variable_name];
49 return true;
50 }
51
52 return false;
53 }
54
[email protected]b94584a2013-02-07 03:02:0855 virtual bool SetVar(const char* variable_name,
56 const std::string& new_value) OVERRIDE {
[email protected]fc586c72010-07-31 16:55:4057 ADD_FAILURE();
58 return false;
59 }
60
[email protected]b94584a2013-02-07 03:02:0861 virtual bool UnSetVar(const char* variable_name) OVERRIDE {
[email protected]fc586c72010-07-31 16:55:4062 ADD_FAILURE();
[email protected]e9032c62010-07-16 03:34:2563 return false;
[email protected]ac7264c2010-07-08 13:32:5164 }
65
[email protected]af71d642010-03-12 10:29:0466 private:
67 std::map<std::string, std::string> variables_;
68
[email protected]76b90d312010-08-03 03:00:5069 DISALLOW_COPY_AND_ASSIGN(MockEnvironment);
[email protected]af71d642010-03-12 10:29:0470};
71
72} // namespace
73
[email protected]d81a63c02013-03-07 08:49:0474TEST(ShellIntegrationTest, GetExistingShortcutLocations) {
75 base::FilePath kProfilePath("Default");
76 const char kExtensionId[] = "test_extension";
77 const char kTemplateFilename[] = "chrome-test_extension-Default.desktop";
78 base::FilePath kTemplateFilepath(kTemplateFilename);
79 const char kNoDisplayDesktopFile[] = "[Desktop Entry]\nNoDisplay=true";
[email protected]af71d642010-03-12 10:29:0480
[email protected]d81a63c02013-03-07 08:49:0481 MessageLoop message_loop;
82 content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
83
84 // No existing shortcuts.
85 {
86 MockEnvironment env;
87 ShellIntegration::ShortcutLocations result =
88 ShellIntegrationLinux::GetExistingShortcutLocations(
89 &env, kProfilePath, kExtensionId);
90 EXPECT_FALSE(result.on_desktop);
91 EXPECT_FALSE(result.in_applications_menu);
92 EXPECT_FALSE(result.in_quick_launch_bar);
93 EXPECT_FALSE(result.hidden);
94 }
95
96 // Shortcut on desktop.
97 {
98 base::ScopedTempDir temp_dir;
99 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
100 base::FilePath desktop_path = temp_dir.path();
101
102 MockEnvironment env;
103 ASSERT_TRUE(file_util::CreateDirectory(desktop_path));
104 ASSERT_FALSE(file_util::WriteFile(
105 desktop_path.AppendASCII(kTemplateFilename),
106 "", 0));
107 ShellIntegration::ShortcutLocations result =
108 ShellIntegrationLinux::GetExistingShortcutLocations(
109 &env, kProfilePath, kExtensionId, desktop_path);
110 EXPECT_TRUE(result.on_desktop);
111 EXPECT_FALSE(result.in_applications_menu);
112 EXPECT_FALSE(result.in_quick_launch_bar);
113 EXPECT_FALSE(result.hidden);
114 }
115
116 // Shortcut in applications directory.
117 {
118 base::ScopedTempDir temp_dir;
119 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
120 base::FilePath apps_path = temp_dir.path().AppendASCII("applications");
121
122 MockEnvironment env;
123 env.Set("XDG_DATA_HOME", temp_dir.path().value());
124 ASSERT_TRUE(file_util::CreateDirectory(apps_path));
125 ASSERT_FALSE(file_util::WriteFile(
126 apps_path.AppendASCII(kTemplateFilename),
127 "", 0));
128 ShellIntegration::ShortcutLocations result =
129 ShellIntegrationLinux::GetExistingShortcutLocations(
130 &env, kProfilePath, kExtensionId);
131 EXPECT_FALSE(result.on_desktop);
132 EXPECT_TRUE(result.in_applications_menu);
133 EXPECT_FALSE(result.in_quick_launch_bar);
134 EXPECT_FALSE(result.hidden);
135 }
136
137 // Shortcut in applications directory with NoDisplay=true.
138 {
139 base::ScopedTempDir temp_dir;
140 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
141 base::FilePath apps_path = temp_dir.path().AppendASCII("applications");
142
143 MockEnvironment env;
144 env.Set("XDG_DATA_HOME", temp_dir.path().value());
145 ASSERT_TRUE(file_util::CreateDirectory(apps_path));
146 ASSERT_TRUE(file_util::WriteFile(
147 apps_path.AppendASCII(kTemplateFilename),
148 kNoDisplayDesktopFile, strlen(kNoDisplayDesktopFile)));
149 ShellIntegration::ShortcutLocations result =
150 ShellIntegrationLinux::GetExistingShortcutLocations(
151 &env, kProfilePath, kExtensionId);
152 // Doesn't count as being in applications menu.
153 EXPECT_FALSE(result.on_desktop);
154 EXPECT_FALSE(result.in_applications_menu);
155 EXPECT_FALSE(result.in_quick_launch_bar);
156 EXPECT_TRUE(result.hidden);
157 }
158
159 // Shortcut on desktop and in applications directory.
160 {
161 base::ScopedTempDir temp_dir1;
162 ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
163 base::FilePath desktop_path = temp_dir1.path();
164
165 base::ScopedTempDir temp_dir2;
166 ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
167 base::FilePath apps_path = temp_dir2.path().AppendASCII("applications");
168
169 MockEnvironment env;
170 ASSERT_TRUE(file_util::CreateDirectory(desktop_path));
171 ASSERT_FALSE(file_util::WriteFile(
172 desktop_path.AppendASCII(kTemplateFilename),
173 "", 0));
174 env.Set("XDG_DATA_HOME", temp_dir2.path().value());
175 ASSERT_TRUE(file_util::CreateDirectory(apps_path));
176 ASSERT_FALSE(file_util::WriteFile(
177 apps_path.AppendASCII(kTemplateFilename),
178 "", 0));
179 ShellIntegration::ShortcutLocations result =
180 ShellIntegrationLinux::GetExistingShortcutLocations(
181 &env, kProfilePath, kExtensionId, desktop_path);
182 EXPECT_TRUE(result.on_desktop);
183 EXPECT_TRUE(result.in_applications_menu);
184 EXPECT_FALSE(result.in_quick_launch_bar);
185 EXPECT_FALSE(result.hidden);
186 }
187}
188
189TEST(ShellIntegrationTest, GetExistingShortcutContents) {
190 const char kTemplateFilename[] = "shortcut-test.desktop";
191 base::FilePath kTemplateFilepath(kTemplateFilename);
[email protected]af71d642010-03-12 10:29:04192 const char kTestData1[] = "a magical testing string";
193 const char kTestData2[] = "a different testing string";
194
195 MessageLoop message_loop;
[email protected]c38831a12011-10-28 12:44:49196 content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
[email protected]af71d642010-03-12 10:29:04197
[email protected]58bf9252013-03-06 04:12:36198 // Test that it searches $XDG_DATA_HOME/applications.
[email protected]af71d642010-03-12 10:29:04199 {
[email protected]ea1a3f62012-11-16 20:34:23200 base::ScopedTempDir temp_dir;
[email protected]af71d642010-03-12 10:29:04201 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
202
[email protected]76b90d312010-08-03 03:00:50203 MockEnvironment env;
204 env.Set("XDG_DATA_HOME", temp_dir.path().value());
[email protected]58bf9252013-03-06 04:12:36205 // Create a file in a non-applications directory. This should be ignored.
[email protected]af71d642010-03-12 10:29:04206 ASSERT_TRUE(file_util::WriteFile(
207 temp_dir.path().AppendASCII(kTemplateFilename),
[email protected]58bf9252013-03-06 04:12:36208 kTestData2, strlen(kTestData2)));
209 ASSERT_TRUE(file_util::CreateDirectory(
210 temp_dir.path().AppendASCII("applications")));
211 ASSERT_TRUE(file_util::WriteFile(
212 temp_dir.path().AppendASCII("applications")
213 .AppendASCII(kTemplateFilename),
[email protected]af71d642010-03-12 10:29:04214 kTestData1, strlen(kTestData1)));
215 std::string contents;
[email protected]d81a63c02013-03-07 08:49:04216 ASSERT_TRUE(
217 ShellIntegrationLinux::GetExistingShortcutContents(
218 &env, kTemplateFilepath, &contents));
[email protected]af71d642010-03-12 10:29:04219 EXPECT_EQ(kTestData1, contents);
220 }
221
[email protected]58bf9252013-03-06 04:12:36222 // Test that it falls back to $HOME/.local/share/applications.
223 {
224 base::ScopedTempDir temp_dir;
225 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
226
227 MockEnvironment env;
228 env.Set("HOME", temp_dir.path().value());
229 ASSERT_TRUE(file_util::CreateDirectory(
230 temp_dir.path().AppendASCII(".local/share/applications")));
231 ASSERT_TRUE(file_util::WriteFile(
232 temp_dir.path().AppendASCII(".local/share/applications")
233 .AppendASCII(kTemplateFilename),
234 kTestData1, strlen(kTestData1)));
235 std::string contents;
[email protected]d81a63c02013-03-07 08:49:04236 ASSERT_TRUE(
237 ShellIntegrationLinux::GetExistingShortcutContents(
238 &env, kTemplateFilepath, &contents));
[email protected]58bf9252013-03-06 04:12:36239 EXPECT_EQ(kTestData1, contents);
240 }
241
242 // Test that it searches $XDG_DATA_DIRS/applications.
[email protected]af71d642010-03-12 10:29:04243 {
[email protected]ea1a3f62012-11-16 20:34:23244 base::ScopedTempDir temp_dir;
[email protected]af71d642010-03-12 10:29:04245 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
246
[email protected]76b90d312010-08-03 03:00:50247 MockEnvironment env;
248 env.Set("XDG_DATA_DIRS", temp_dir.path().value());
[email protected]af71d642010-03-12 10:29:04249 ASSERT_TRUE(file_util::CreateDirectory(
250 temp_dir.path().AppendASCII("applications")));
251 ASSERT_TRUE(file_util::WriteFile(
252 temp_dir.path().AppendASCII("applications")
253 .AppendASCII(kTemplateFilename),
254 kTestData2, strlen(kTestData2)));
255 std::string contents;
[email protected]d81a63c02013-03-07 08:49:04256 ASSERT_TRUE(
257 ShellIntegrationLinux::GetExistingShortcutContents(
258 &env, kTemplateFilepath, &contents));
[email protected]af71d642010-03-12 10:29:04259 EXPECT_EQ(kTestData2, contents);
260 }
261
[email protected]58bf9252013-03-06 04:12:36262 // Test that it searches $X/applications for each X in $XDG_DATA_DIRS.
[email protected]af71d642010-03-12 10:29:04263 {
[email protected]58bf9252013-03-06 04:12:36264 base::ScopedTempDir temp_dir1;
265 ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
266 base::ScopedTempDir temp_dir2;
267 ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
[email protected]af71d642010-03-12 10:29:04268
[email protected]76b90d312010-08-03 03:00:50269 MockEnvironment env;
[email protected]58bf9252013-03-06 04:12:36270 env.Set("XDG_DATA_DIRS", temp_dir1.path().value() + ":" +
271 temp_dir2.path().value());
272 // Create a file in a non-applications directory. This should be ignored.
[email protected]af71d642010-03-12 10:29:04273 ASSERT_TRUE(file_util::WriteFile(
[email protected]58bf9252013-03-06 04:12:36274 temp_dir1.path().AppendASCII(kTemplateFilename),
[email protected]af71d642010-03-12 10:29:04275 kTestData1, strlen(kTestData1)));
[email protected]58bf9252013-03-06 04:12:36276 // Only create a findable desktop file in the second path.
277 ASSERT_TRUE(file_util::CreateDirectory(
278 temp_dir2.path().AppendASCII("applications")));
[email protected]af71d642010-03-12 10:29:04279 ASSERT_TRUE(file_util::WriteFile(
[email protected]58bf9252013-03-06 04:12:36280 temp_dir2.path().AppendASCII("applications")
[email protected]af71d642010-03-12 10:29:04281 .AppendASCII(kTemplateFilename),
282 kTestData2, strlen(kTestData2)));
283 std::string contents;
[email protected]d81a63c02013-03-07 08:49:04284 ASSERT_TRUE(
285 ShellIntegrationLinux::GetExistingShortcutContents(
286 &env, kTemplateFilepath, &contents));
287 EXPECT_EQ(kTestData2, contents);
288 }
289}
290
[email protected]0b7df36d2012-07-11 09:50:47291TEST(ShellIntegrationTest, GetWebShortcutFilename) {
[email protected]b96aa932009-08-12 21:34:49292 const struct {
[email protected]650b2d52013-02-10 03:41:45293 const base::FilePath::CharType* path;
[email protected]b96aa932009-08-12 21:34:49294 const char* url;
295 } test_cases[] = {
296 { FPL("http___foo_.desktop"), "http://foo" },
297 { FPL("http___foo_bar_.desktop"), "http://foo/bar/" },
298 { FPL("http___foo_bar_a=b&c=d.desktop"), "http://foo/bar?a=b&c=d" },
299
300 // Now we're starting to be more evil...
301 { FPL("http___foo_.desktop"), "http://foo/bar/baz/../../../../../" },
302 { FPL("http___foo_.desktop"), "http://foo/bar/././../baz/././../" },
303 { FPL("http___.._.desktop"), "http://../../../../" },
304 };
305 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
[email protected]4f260d02010-12-23 18:35:42306 EXPECT_EQ(std::string(chrome::kBrowserProcessExecutableName) + "-" +
[email protected]42896802009-08-28 23:39:44307 test_cases[i].path,
[email protected]0b7df36d2012-07-11 09:50:47308 ShellIntegrationLinux::GetWebShortcutFilename(
[email protected]42896802009-08-28 23:39:44309 GURL(test_cases[i].url)).value()) <<
310 " while testing " << test_cases[i].url;
[email protected]b96aa932009-08-12 21:34:49311 }
312}
313
[email protected]a2778d32011-12-01 07:49:34314TEST(ShellIntegrationTest, GetDesktopFileContents) {
[email protected]14fbaed2013-05-02 07:54:02315 const base::FilePath kChromeExePath("/opt/google/chrome/google-chrome");
[email protected]b96aa932009-08-12 21:34:49316 const struct {
317 const char* url;
318 const char* title;
[email protected]0b303cc2009-09-28 22:35:15319 const char* icon_name;
[email protected]d81a63c02013-03-07 08:49:04320 bool nodisplay;
[email protected]b96aa932009-08-12 21:34:49321 const char* expected_output;
322 } test_cases[] = {
[email protected]b96aa932009-08-12 21:34:49323 // Real-world case.
324 { "http://gmail.com",
325 "GMail",
[email protected]0b303cc2009-09-28 22:35:15326 "chrome-http__gmail.com",
[email protected]d81a63c02013-03-07 08:49:04327 false,
[email protected]b96aa932009-08-12 21:34:49328
[email protected]82810fe12009-09-25 16:21:57329 "#!/usr/bin/env xdg-open\n"
[email protected]b96aa932009-08-12 21:34:49330 "[Desktop Entry]\n"
331 "Version=1.0\n"
[email protected]b96aa932009-08-12 21:34:49332 "Terminal=false\n"
[email protected]b96aa932009-08-12 21:34:49333 "Type=Application\n"
[email protected]82810fe12009-09-25 16:21:57334 "Name=GMail\n"
[email protected]b10392932011-03-08 21:28:14335 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
[email protected]0a96c3f2011-05-11 22:10:20336 "Icon=chrome-http__gmail.com\n"
[email protected]a2778d32011-12-01 07:49:34337#if !defined(USE_AURA)
[email protected]07753f0f2013-02-05 07:52:59338 // Aura Chrome does not (yet) set WMClass, so we only expect
339 // StartupWMClass on non-Aura builds.
[email protected]a0b60cfd2011-04-06 18:02:41340 "StartupWMClass=gmail.com\n"
[email protected]a2778d32011-12-01 07:49:34341#endif
[email protected]82810fe12009-09-25 16:21:57342 },
343
[email protected]0b303cc2009-09-28 22:35:15344 // Make sure that empty icons are replaced by the chrome icon.
345 { "http://gmail.com",
346 "GMail",
347 "",
[email protected]d81a63c02013-03-07 08:49:04348 false,
[email protected]0b303cc2009-09-28 22:35:15349
[email protected]0b303cc2009-09-28 22:35:15350 "#!/usr/bin/env xdg-open\n"
[email protected]0a96c3f2011-05-11 22:10:20351 "[Desktop Entry]\n"
[email protected]14fbaed2013-05-02 07:54:02352 "Version=1.0\n"
353 "Terminal=false\n"
354 "Type=Application\n"
[email protected]0b303cc2009-09-28 22:35:15355 "Name=GMail\n"
[email protected]b10392932011-03-08 21:28:14356 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
[email protected]14fbaed2013-05-02 07:54:02357 "Icon=chromium-browser\n"
[email protected]a2778d32011-12-01 07:49:34358#if !defined(USE_AURA)
[email protected]07753f0f2013-02-05 07:52:59359 // Aura Chrome does not (yet) set WMClass, so we only expect
360 // StartupWMClass on non-Aura builds.
[email protected]a0b60cfd2011-04-06 18:02:41361 "StartupWMClass=gmail.com\n"
[email protected]a2778d32011-12-01 07:49:34362#endif
[email protected]0b303cc2009-09-28 22:35:15363 },
364
[email protected]d81a63c02013-03-07 08:49:04365 // Test adding NoDisplay=true.
366 { "http://gmail.com",
367 "GMail",
368 "chrome-http__gmail.com",
369 true,
370
[email protected]d81a63c02013-03-07 08:49:04371 "#!/usr/bin/env xdg-open\n"
372 "[Desktop Entry]\n"
[email protected]14fbaed2013-05-02 07:54:02373 "Version=1.0\n"
374 "Terminal=false\n"
375 "Type=Application\n"
[email protected]d81a63c02013-03-07 08:49:04376 "Name=GMail\n"
377 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
378 "Icon=chrome-http__gmail.com\n"
379 "NoDisplay=true\n"
380#if !defined(USE_AURA)
381 // Aura Chrome does not (yet) set WMClass, so we only expect
382 // StartupWMClass on non-Aura builds.
383 "StartupWMClass=gmail.com\n"
384#endif
385 },
386
[email protected]b96aa932009-08-12 21:34:49387 // Now we're starting to be more evil...
388 { "http://evil.com/evil --join-the-b0tnet",
389 "Ownz0red\nExec=rm -rf /",
[email protected]0b303cc2009-09-28 22:35:15390 "chrome-http__evil.com_evil",
[email protected]d81a63c02013-03-07 08:49:04391 false,
[email protected]b96aa932009-08-12 21:34:49392
[email protected]82810fe12009-09-25 16:21:57393 "#!/usr/bin/env xdg-open\n"
[email protected]0a96c3f2011-05-11 22:10:20394 "[Desktop Entry]\n"
[email protected]14fbaed2013-05-02 07:54:02395 "Version=1.0\n"
396 "Terminal=false\n"
397 "Type=Application\n"
[email protected]b96aa932009-08-12 21:34:49398 "Name=http://evil.com/evil%20--join-the-b0tnet\n"
399 "Exec=/opt/google/chrome/google-chrome "
[email protected]b10392932011-03-08 21:28:14400 "--app=http://evil.com/evil%20--join-the-b0tnet\n"
[email protected]0a96c3f2011-05-11 22:10:20401 "Icon=chrome-http__evil.com_evil\n"
[email protected]a2778d32011-12-01 07:49:34402#if !defined(USE_AURA)
[email protected]07753f0f2013-02-05 07:52:59403 // Aura Chrome does not (yet) set WMClass, so we only expect
404 // StartupWMClass on non-Aura builds.
[email protected]a0b60cfd2011-04-06 18:02:41405 "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n"
[email protected]a2778d32011-12-01 07:49:34406#endif
[email protected]b96aa932009-08-12 21:34:49407 },
[email protected]82810fe12009-09-25 16:21:57408 { "http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red",
409 "Innocent Title",
[email protected]0b303cc2009-09-28 22:35:15410 "chrome-http__evil.com_evil",
[email protected]d81a63c02013-03-07 08:49:04411 false,
[email protected]82810fe12009-09-25 16:21:57412
[email protected]82810fe12009-09-25 16:21:57413 "#!/usr/bin/env xdg-open\n"
[email protected]0a96c3f2011-05-11 22:10:20414 "[Desktop Entry]\n"
[email protected]14fbaed2013-05-02 07:54:02415 "Version=1.0\n"
416 "Terminal=false\n"
417 "Type=Application\n"
[email protected]82810fe12009-09-25 16:21:57418 "Name=Innocent Title\n"
419 "Exec=/opt/google/chrome/google-chrome "
[email protected]b10392932011-03-08 21:28:14420 "\"--app=http://evil.com/evil;%20rm%20-rf%20/;%20%22;%20rm%20"
421 // Note: $ is escaped as \$ within an arg to Exec, and then
422 // the \ is escaped as \\ as all strings in a Desktop file should
423 // be; finally, \\ becomes \\\\ when represented in a C++ string!
424 "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
[email protected]0a96c3f2011-05-11 22:10:20425 "Icon=chrome-http__evil.com_evil\n"
[email protected]a2778d32011-12-01 07:49:34426#if !defined(USE_AURA)
[email protected]07753f0f2013-02-05 07:52:59427 // Aura Chrome does not (yet) set WMClass, so we only expect
428 // StartupWMClass on non-Aura builds.
[email protected]a0b60cfd2011-04-06 18:02:41429 "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20"
430 "rm%20-rf%20$HOME%20%3Eownz0red\n"
[email protected]a2778d32011-12-01 07:49:34431#endif
[email protected]82810fe12009-09-25 16:21:57432 },
[email protected]790613c2009-12-30 14:49:41433 { "http://evil.com/evil | cat `echo ownz0red` >/dev/null",
[email protected]82810fe12009-09-25 16:21:57434 "Innocent Title",
[email protected]0b303cc2009-09-28 22:35:15435 "chrome-http__evil.com_evil",
[email protected]d81a63c02013-03-07 08:49:04436 false,
[email protected]82810fe12009-09-25 16:21:57437
[email protected]82810fe12009-09-25 16:21:57438 "#!/usr/bin/env xdg-open\n"
[email protected]0a96c3f2011-05-11 22:10:20439 "[Desktop Entry]\n"
[email protected]14fbaed2013-05-02 07:54:02440 "Version=1.0\n"
441 "Terminal=false\n"
442 "Type=Application\n"
[email protected]82810fe12009-09-25 16:21:57443 "Name=Innocent Title\n"
444 "Exec=/opt/google/chrome/google-chrome "
[email protected]b10392932011-03-08 21:28:14445 "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
446 "%60%20%3E/dev/null\n"
[email protected]0a96c3f2011-05-11 22:10:20447 "Icon=chrome-http__evil.com_evil\n"
[email protected]a2778d32011-12-01 07:49:34448#if !defined(USE_AURA)
[email protected]07753f0f2013-02-05 07:52:59449 // Aura Chrome does not (yet) set WMClass, so we only expect
450 // StartupWMClass on non-Aura builds.
[email protected]a0b60cfd2011-04-06 18:02:41451 "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red"
452 "%60%20%3E_dev_null\n"
[email protected]a2778d32011-12-01 07:49:34453#endif
[email protected]82810fe12009-09-25 16:21:57454 },
[email protected]b96aa932009-08-12 21:34:49455 };
[email protected]07753f0f2013-02-05 07:52:59456
[email protected]b96aa932009-08-12 21:34:49457 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
[email protected]b10392932011-03-08 21:28:14458 SCOPED_TRACE(i);
[email protected]a0b60cfd2011-04-06 18:02:41459 EXPECT_EQ(
460 test_cases[i].expected_output,
[email protected]98566d7a2012-04-17 00:28:56461 ShellIntegrationLinux::GetDesktopFileContents(
[email protected]14fbaed2013-05-02 07:54:02462 kChromeExePath,
[email protected]a0b60cfd2011-04-06 18:02:41463 web_app::GenerateApplicationNameFromURL(GURL(test_cases[i].url)),
464 GURL(test_cases[i].url),
[email protected]007b3f82013-04-09 08:46:45465 std::string(),
[email protected]650b2d52013-02-10 03:41:45466 base::FilePath(),
[email protected]a0b60cfd2011-04-06 18:02:41467 ASCIIToUTF16(test_cases[i].title),
[email protected]5951c852012-06-20 00:12:53468 test_cases[i].icon_name,
[email protected]d81a63c02013-03-07 08:49:04469 base::FilePath(),
470 test_cases[i].nodisplay));
[email protected]b96aa932009-08-12 21:34:49471 }
472}
[email protected]d81a63c02013-03-07 08:49:04473
[email protected]a3c25952013-05-02 13:16:06474TEST(ShellIntegrationTest, GetDirectoryFileContents) {
475 const struct {
476 const char* title;
477 const char* icon_name;
478 const char* expected_output;
479 } test_cases[] = {
480 // Real-world case.
481 { "Chrome Apps",
482 "chrome-apps",
483
484 "[Desktop Entry]\n"
485 "Version=1.0\n"
486 "Type=Directory\n"
487 "Name=Chrome Apps\n"
488 "Icon=chrome-apps\n"
489 },
490
491 // Make sure that empty icons are replaced by the chrome icon.
492 { "Chrome Apps",
493 "",
494
495 "[Desktop Entry]\n"
496 "Version=1.0\n"
497 "Type=Directory\n"
498 "Name=Chrome Apps\n"
499 "Icon=chromium-browser\n"
500 },
501 };
502
503 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
504 SCOPED_TRACE(i);
505 EXPECT_EQ(
506 test_cases[i].expected_output,
507 ShellIntegrationLinux::GetDirectoryFileContents(
508 ASCIIToUTF16(test_cases[i].title),
509 test_cases[i].icon_name));
510 }
511}
512
[email protected]12f520c2010-01-06 18:11:15513#endif