1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/files/file_path.h"
6 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
7 #include "chrome/common/extensions/sync_helper.h"
8 #include "extensions/common/error_utils.h"
9 #include "extensions/common/extension.h"
10 #include "extensions/common/manifest.h"
11 #include "extensions/common/manifest_constants.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "url/gurl.h"
14
15 namespace extensions {
16
17 namespace keys = manifest_keys;
18 namespace errors = manifest_errors;
19
20 class ExtensionSyncTypeTest : public testing::Test {
21 protected:
22 enum SyncTestExtensionType {
23 EXTENSION,
24 APP,
25 USER_SCRIPT,
26 THEME
27 };
28
MakeSyncTestExtensionWithPluginPermission(SyncTestExtensionType type,const GURL & update_url,const GURL & launch_url,Manifest::Location location,const base::FilePath & extension_path,int creation_flags,int num_plugins,bool has_plugin_permission,const std::string & expected_error)29 static scoped_refptr<Extension> MakeSyncTestExtensionWithPluginPermission(
30 SyncTestExtensionType type,
31 const GURL& update_url,
32 const GURL& launch_url,
33 Manifest::Location location,
34 const base::FilePath& extension_path,
35 int creation_flags,
36 int num_plugins,
37 bool has_plugin_permission,
38 const std::string& expected_error) {
39 base::DictionaryValue source;
40 source.SetString(keys::kName, "PossiblySyncableExtension");
41 source.SetString(keys::kVersion, "0.0.0.0");
42 if (type == APP)
43 source.SetString(keys::kApp, "true");
44 if (type == THEME)
45 source.Set(keys::kTheme, new base::DictionaryValue());
46 if (!update_url.is_empty()) {
47 source.SetString(keys::kUpdateURL, update_url.spec());
48 }
49 if (!launch_url.is_empty()) {
50 source.SetString(keys::kLaunchWebURL, launch_url.spec());
51 }
52 if (type != THEME) {
53 source.SetBoolean(keys::kConvertedFromUserScript, type == USER_SCRIPT);
54 if (num_plugins >= 0) {
55 base::ListValue* plugins = new base::ListValue();
56 for (int i = 0; i < num_plugins; ++i) {
57 base::DictionaryValue* plugin = new base::DictionaryValue();
58 plugin->SetString(keys::kPluginsPath, std::string());
59 plugins->Set(i, plugin);
60 }
61 source.Set(keys::kPlugins, plugins);
62 }
63 }
64 if (has_plugin_permission) {
65 base::ListValue* plugins = new base::ListValue();
66 plugins->Set(0, new base::StringValue("plugin"));
67 source.Set(keys::kPermissions, plugins);
68 }
69
70 std::string error;
71 scoped_refptr<Extension> extension = Extension::Create(
72 extension_path, location, source, creation_flags, &error);
73 if (expected_error == "")
74 EXPECT_TRUE(extension.get());
75 else
76 EXPECT_FALSE(extension.get());
77 EXPECT_EQ(expected_error, error);
78 return extension;
79 }
80
MakeSyncTestExtension(SyncTestExtensionType type,const GURL & update_url,const GURL & launch_url,Manifest::Location location,const base::FilePath & extension_path,int creation_flags)81 static scoped_refptr<Extension> MakeSyncTestExtension(
82 SyncTestExtensionType type,
83 const GURL& update_url,
84 const GURL& launch_url,
85 Manifest::Location location,
86 const base::FilePath& extension_path,
87 int creation_flags) {
88 return MakeSyncTestExtensionWithPluginPermission(
89 type, update_url, launch_url, location, extension_path,
90 creation_flags, -1, false, "");
91 }
92
93 static const char kValidUpdateUrl1[];
94 static const char kValidUpdateUrl2[];
95 };
96
97 const char ExtensionSyncTypeTest::kValidUpdateUrl1[] =
98 "http://clients2.google.com/service/update2/crx";
99 const char ExtensionSyncTypeTest::kValidUpdateUrl2[] =
100 "https://clients2.google.com/service/update2/crx";
101
TEST_F(ExtensionSyncTypeTest,NormalExtensionNoUpdateUrl)102 TEST_F(ExtensionSyncTypeTest, NormalExtensionNoUpdateUrl) {
103 scoped_refptr<Extension> extension(
104 MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
105 Manifest::INTERNAL, base::FilePath(),
106 Extension::NO_FLAGS));
107 EXPECT_TRUE(sync_helper::IsSyncableExtension(extension.get()));
108 }
109
TEST_F(ExtensionSyncTypeTest,UserScriptValidUpdateUrl)110 TEST_F(ExtensionSyncTypeTest, UserScriptValidUpdateUrl) {
111 scoped_refptr<Extension> extension(
112 MakeSyncTestExtension(USER_SCRIPT, GURL(kValidUpdateUrl1), GURL(),
113 Manifest::INTERNAL, base::FilePath(),
114 Extension::NO_FLAGS));
115 EXPECT_TRUE(sync_helper::IsSyncableExtension(extension.get()));
116 }
117
TEST_F(ExtensionSyncTypeTest,UserScriptNoUpdateUrl)118 TEST_F(ExtensionSyncTypeTest, UserScriptNoUpdateUrl) {
119 scoped_refptr<Extension> extension(
120 MakeSyncTestExtension(USER_SCRIPT, GURL(), GURL(),
121 Manifest::INTERNAL, base::FilePath(),
122 Extension::NO_FLAGS));
123 EXPECT_FALSE(sync_helper::IsSyncableExtension(extension.get()));
124 }
125
TEST_F(ExtensionSyncTypeTest,ThemeNoUpdateUrl)126 TEST_F(ExtensionSyncTypeTest, ThemeNoUpdateUrl) {
127 scoped_refptr<Extension> extension(
128 MakeSyncTestExtension(THEME, GURL(), GURL(),
129 Manifest::INTERNAL, base::FilePath(),
130 Extension::NO_FLAGS));
131 EXPECT_FALSE(sync_helper::IsSyncableExtension(extension.get()));
132 EXPECT_FALSE(sync_helper::IsSyncableApp(extension.get()));
133 }
134
TEST_F(ExtensionSyncTypeTest,AppWithLaunchUrl)135 TEST_F(ExtensionSyncTypeTest, AppWithLaunchUrl) {
136 scoped_refptr<Extension> extension(
137 MakeSyncTestExtension(EXTENSION, GURL(), GURL("http://www.google.com"),
138 Manifest::INTERNAL, base::FilePath(),
139 Extension::NO_FLAGS));
140 EXPECT_TRUE(sync_helper::IsSyncableApp(extension.get()));
141 }
142
TEST_F(ExtensionSyncTypeTest,ExtensionExternal)143 TEST_F(ExtensionSyncTypeTest, ExtensionExternal) {
144 scoped_refptr<Extension> extension(
145 MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
146 Manifest::EXTERNAL_PREF, base::FilePath(),
147 Extension::NO_FLAGS));
148 EXPECT_FALSE(sync_helper::IsSyncableExtension(extension.get()));
149 }
150
TEST_F(ExtensionSyncTypeTest,UserScriptThirdPartyUpdateUrl)151 TEST_F(ExtensionSyncTypeTest, UserScriptThirdPartyUpdateUrl) {
152 scoped_refptr<Extension> extension(
153 MakeSyncTestExtension(
154 USER_SCRIPT, GURL("http://third-party.update_url.com"), GURL(),
155 Manifest::INTERNAL, base::FilePath(), Extension::NO_FLAGS));
156 EXPECT_FALSE(sync_helper::IsSyncableExtension(extension.get()));
157 }
158
TEST_F(ExtensionSyncTypeTest,OnlyDisplayAppsInLauncher)159 TEST_F(ExtensionSyncTypeTest, OnlyDisplayAppsInLauncher) {
160 scoped_refptr<Extension> extension(
161 MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
162 Manifest::INTERNAL, base::FilePath(),
163 Extension::NO_FLAGS));
164
165 EXPECT_FALSE(extension->ShouldDisplayInAppLauncher());
166 EXPECT_FALSE(extension->ShouldDisplayInNewTabPage());
167
168 scoped_refptr<Extension> app(
169 MakeSyncTestExtension(APP, GURL(), GURL("http://www.google.com"),
170 Manifest::INTERNAL, base::FilePath(),
171 Extension::NO_FLAGS));
172 EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
173 EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
174 }
175
TEST_F(ExtensionSyncTypeTest,DisplayInXManifestProperties)176 TEST_F(ExtensionSyncTypeTest, DisplayInXManifestProperties) {
177 base::DictionaryValue manifest;
178 manifest.SetString(keys::kName, "TestComponentApp");
179 manifest.SetString(keys::kVersion, "0.0.0.0");
180 manifest.SetString(keys::kApp, "true");
181 manifest.SetString(keys::kPlatformAppBackgroundPage, std::string());
182
183 std::string error;
184 scoped_refptr<Extension> app;
185
186 // Default to true.
187 app = Extension::Create(
188 base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
189 EXPECT_EQ(error, std::string());
190 EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
191 EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
192
193 // Value display_in_NTP defaults to display_in_launcher.
194 manifest.SetBoolean(keys::kDisplayInLauncher, false);
195 app = Extension::Create(
196 base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
197 EXPECT_EQ(error, std::string());
198 EXPECT_FALSE(app->ShouldDisplayInAppLauncher());
199 EXPECT_FALSE(app->ShouldDisplayInNewTabPage());
200
201 // Value display_in_NTP = true overriding display_in_launcher = false.
202 manifest.SetBoolean(keys::kDisplayInNewTabPage, true);
203 app = Extension::Create(
204 base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
205 EXPECT_EQ(error, std::string());
206 EXPECT_FALSE(app->ShouldDisplayInAppLauncher());
207 EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
208
209 // Value display_in_NTP = false only, overrides default = true.
210 manifest.Remove(keys::kDisplayInLauncher, NULL);
211 manifest.SetBoolean(keys::kDisplayInNewTabPage, false);
212 app = Extension::Create(
213 base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
214 EXPECT_EQ(error, std::string());
215 EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
216 EXPECT_FALSE(app->ShouldDisplayInNewTabPage());
217
218 // Error checking.
219 manifest.SetString(keys::kDisplayInNewTabPage, "invalid");
220 app = Extension::Create(
221 base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
222 EXPECT_EQ(error, std::string(errors::kInvalidDisplayInNewTabPage));
223 }
224
TEST_F(ExtensionSyncTypeTest,OnlySyncInternal)225 TEST_F(ExtensionSyncTypeTest, OnlySyncInternal) {
226 scoped_refptr<Extension> extension_internal(
227 MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
228 Manifest::INTERNAL, base::FilePath(),
229 Extension::NO_FLAGS));
230 EXPECT_TRUE(sync_helper::IsSyncable(extension_internal.get()));
231
232 scoped_refptr<Extension> extension_noninternal(
233 MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
234 Manifest::COMPONENT, base::FilePath(),
235 Extension::NO_FLAGS));
236 EXPECT_FALSE(sync_helper::IsSyncable(extension_noninternal.get()));
237 }
238
TEST_F(ExtensionSyncTypeTest,DontSyncDefault)239 TEST_F(ExtensionSyncTypeTest, DontSyncDefault) {
240 scoped_refptr<Extension> extension_default(
241 MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
242 Manifest::INTERNAL, base::FilePath(),
243 Extension::WAS_INSTALLED_BY_DEFAULT));
244 EXPECT_FALSE(sync_helper::IsSyncable(extension_default.get()));
245 }
246
247 // These plugin tests don't make sense on Chrome OS, where extension plugins
248 // are not allowed.
249 #if !defined(OS_CHROMEOS)
TEST_F(ExtensionSyncTypeTest,ExtensionWithEmptyPlugins)250 TEST_F(ExtensionSyncTypeTest, ExtensionWithEmptyPlugins) {
251 scoped_refptr<Extension> extension(
252 MakeSyncTestExtensionWithPluginPermission(
253 EXTENSION, GURL(), GURL(),
254 Manifest::INTERNAL, base::FilePath(),
255 Extension::NO_FLAGS, 0, false, ""));
256 if (extension.get())
257 EXPECT_TRUE(sync_helper::IsSyncableExtension(extension.get()));
258 }
259
TEST_F(ExtensionSyncTypeTest,ExtensionWithPlugin)260 TEST_F(ExtensionSyncTypeTest, ExtensionWithPlugin) {
261 scoped_refptr<Extension> extension(
262 MakeSyncTestExtensionWithPluginPermission(
263 EXTENSION, GURL(), GURL(),
264 Manifest::INTERNAL, base::FilePath(),
265 Extension::NO_FLAGS, 1, false, ""));
266 if (extension.get())
267 EXPECT_FALSE(sync_helper::IsSyncableExtension(extension.get()));
268 }
269
TEST_F(ExtensionSyncTypeTest,ExtensionWithTwoPlugins)270 TEST_F(ExtensionSyncTypeTest, ExtensionWithTwoPlugins) {
271 scoped_refptr<Extension> extension(
272 MakeSyncTestExtensionWithPluginPermission(
273 EXTENSION, GURL(), GURL(),
274 Manifest::INTERNAL, base::FilePath(),
275 Extension::NO_FLAGS, 2, false, ""));
276 if (extension.get())
277 EXPECT_FALSE(sync_helper::IsSyncableExtension(extension.get()));
278 }
279
TEST_F(ExtensionSyncTypeTest,ExtensionWithPluginPermission)280 TEST_F(ExtensionSyncTypeTest, ExtensionWithPluginPermission) {
281 // Specifying the "plugin" permission in the manifest is an error.
282 scoped_refptr<Extension> extension(
283 MakeSyncTestExtensionWithPluginPermission(
284 EXTENSION, GURL(), GURL(),
285 Manifest::INTERNAL, base::FilePath(),
286 Extension::NO_FLAGS, 0, true,
287 ErrorUtils::FormatErrorMessage(
288 errors::kPermissionNotAllowedInManifest, "plugin")));
289 }
290
291 #endif // !defined(OS_CHROMEOS)
292
293 } // namespace extensions
294