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/extension.h" 8 #include "chrome/common/extensions/extension_manifest_constants.h" 9 #include "chrome/common/extensions/manifest.h" 10 #include "chrome/common/extensions/sync_helper.h" 11 #include "extensions/common/error_utils.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "url/gurl.h" 14 15 namespace keys = extension_manifest_keys; 16 namespace errors = extension_manifest_errors; 17 18 namespace extensions { 19 20 class ExtensionSyncTypeTest : public testing::Test { 21 protected: 22 enum SyncTestExtensionType { 23 EXTENSION, 24 APP, 25 USER_SCRIPT, 26 THEME 27 }; 28 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 ListValue* plugins = new ListValue(); 66 plugins->Set(0, new 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 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 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 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 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 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 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 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 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 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 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 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 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) 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 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 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 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