| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 "chrome/common/extensions/manifest.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <set> | |
| 9 #include <string> | |
| 10 | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/utf_string_conversions.h" | |
| 13 #include "base/values.h" | |
| 14 #include "chrome/common/extensions/extension_constants.h" | |
| 15 #include "chrome/common/extensions/extension_error_utils.h" | |
| 16 #include "testing/gtest/include/gtest/gtest.h" | |
| 17 | |
| 18 namespace keys = extension_manifest_keys; | |
| 19 namespace errors = extension_manifest_errors; | |
| 20 | |
| 21 namespace extensions { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // Keys that define types. | |
| 26 const char* kTypeKeys[] = { | |
| 27 keys::kApp, | |
| 28 keys::kTheme, | |
| 29 keys::kPlatformApp | |
| 30 }; | |
| 31 | |
| 32 // Keys that are not accesible by themes. | |
| 33 const char* kNotThemeKeys[] = { | |
| 34 keys::kBrowserAction, | |
| 35 keys::kPageAction, | |
| 36 keys::kPageActions, | |
| 37 keys::kChromeURLOverrides, | |
| 38 keys::kPermissions, | |
| 39 keys::kOptionalPermissions, | |
| 40 keys::kOptionsPage, | |
| 41 keys::kBackground, | |
| 42 keys::kOfflineEnabled, | |
| 43 keys::kMinimumChromeVersion, | |
| 44 keys::kRequirements, | |
| 45 keys::kConvertedFromUserScript, | |
| 46 keys::kNaClModules, | |
| 47 keys::kPlugins, | |
| 48 keys::kContentScripts, | |
| 49 keys::kOmnibox, | |
| 50 keys::kDevToolsPage, | |
| 51 keys::kSidebar, | |
| 52 keys::kHomepageURL, | |
| 53 keys::kContentSecurityPolicy, | |
| 54 keys::kFileBrowserHandlers, | |
| 55 keys::kIncognito, | |
| 56 keys::kInputComponents, | |
| 57 keys::kTtsEngine, | |
| 58 keys::kIntents | |
| 59 }; | |
| 60 | |
| 61 // Keys that are not accessible by hosted apps. | |
| 62 const char* kNotHostedAppKeys[] = { | |
| 63 keys::kBrowserAction, | |
| 64 keys::kPageAction, | |
| 65 keys::kPageActions, | |
| 66 keys::kChromeURLOverrides, | |
| 67 keys::kContentScripts, | |
| 68 keys::kOmnibox, | |
| 69 keys::kDevToolsPage, | |
| 70 keys::kSidebar, | |
| 71 keys::kHomepageURL, | |
| 72 keys::kContentSecurityPolicy, | |
| 73 keys::kFileBrowserHandlers, | |
| 74 keys::kIncognito, | |
| 75 keys::kInputComponents, | |
| 76 keys::kTtsEngine, | |
| 77 keys::kIntents | |
| 78 }; | |
| 79 | |
| 80 // Keys not accessible by packaged aps. | |
| 81 const char* kNotPackagedAppKeys[] = { | |
| 82 keys::kBrowserAction, | |
| 83 keys::kPageAction, | |
| 84 keys::kPageActions, | |
| 85 keys::kChromeURLOverrides, | |
| 86 }; | |
| 87 | |
| 88 // Keys not accessible by platform apps. | |
| 89 const char* kNotPlatformAppKeys[] = { | |
| 90 keys::kBrowserAction, | |
| 91 keys::kPageAction, | |
| 92 keys::kPageActions, | |
| 93 keys::kChromeURLOverrides, | |
| 94 keys::kContentScripts, | |
| 95 keys::kOmnibox, | |
| 96 keys::kDevToolsPage, | |
| 97 keys::kSidebar, | |
| 98 keys::kHomepageURL, | |
| 99 }; | |
| 100 | |
| 101 // Returns all the manifest keys not including those in |filtered| or kTypeKeys. | |
| 102 std::set<std::string> GetAccessibleKeys(const char* filtered[], size_t length) { | |
| 103 std::set<std::string> all_keys = Manifest::GetAllKnownKeys(); | |
| 104 std::set<std::string> filtered_keys(filtered, filtered + length); | |
| 105 | |
| 106 // Starting with all possible manfiest keys, remove the keys that aren't | |
| 107 // accessible for the given type. | |
| 108 std::set<std::string> intermediate; | |
| 109 std::set_difference(all_keys.begin(), all_keys.end(), | |
| 110 filtered_keys.begin(), filtered_keys.end(), | |
| 111 std::insert_iterator<std::set<std::string> >( | |
| 112 intermediate, intermediate.begin())); | |
| 113 | |
| 114 // Then remove the keys that specify types (app, platform_app, etc.). | |
| 115 std::set<std::string> result; | |
| 116 std::set<std::string> type_keys( | |
| 117 kTypeKeys, kTypeKeys + ARRAYSIZE_UNSAFE(kTypeKeys)); | |
| 118 std::set_difference(intermediate.begin(), intermediate.end(), | |
| 119 type_keys.begin(), type_keys.end(), | |
| 120 std::insert_iterator<std::set<std::string> >( | |
| 121 result, result.begin())); | |
| 122 | |
| 123 return result; | |
| 124 } | |
| 125 | |
| 126 } // namespace | |
| 127 | |
| 128 class ManifestTest : public testing::Test { | |
| 129 public: | |
| 130 ManifestTest() : default_value_("test") {} | |
| 131 | |
| 132 protected: | |
| 133 void AssertType(Manifest* manifest, Manifest::Type type) { | |
| 134 EXPECT_EQ(type, manifest->GetType()); | |
| 135 EXPECT_EQ(type == Manifest::kTypeTheme, manifest->IsTheme()); | |
| 136 EXPECT_EQ(type == Manifest::kTypePlatformApp, manifest->IsPlatformApp()); | |
| 137 EXPECT_EQ(type == Manifest::kTypePackagedApp, manifest->IsPackagedApp()); | |
| 138 EXPECT_EQ(type == Manifest::kTypeHostedApp, manifest->IsHostedApp()); | |
| 139 } | |
| 140 | |
| 141 void TestRestrictedKeys(Manifest* manifest, | |
| 142 const char* restricted_keys[], | |
| 143 size_t restricted_keys_length) { | |
| 144 // Verify that the keys on the restricted key list for the given manifest | |
| 145 // fail validation and are filtered out. | |
| 146 DictionaryValue* value = manifest->value(); | |
| 147 for (size_t i = 0; i < restricted_keys_length; ++i) { | |
| 148 std::string error, str; | |
| 149 value->Set(restricted_keys[i], Value::CreateStringValue(default_value_)); | |
| 150 EXPECT_FALSE(manifest->ValidateManifest(&error)); | |
| 151 EXPECT_EQ(error, ExtensionErrorUtils::FormatErrorMessage( | |
| 152 errors::kFeatureNotAllowed, restricted_keys[i])); | |
| 153 EXPECT_FALSE(manifest->GetString(restricted_keys[i], &str)); | |
| 154 EXPECT_TRUE(value->Remove(restricted_keys[i], NULL)); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 std::string default_value_; | |
| 159 }; | |
| 160 | |
| 161 // Verifies that extensions can access the correct keys. | |
| 162 TEST_F(ManifestTest, Extension) { | |
| 163 // Generate the list of keys accessible by extensions. | |
| 164 std::set<std::string> extension_keys = GetAccessibleKeys(NULL, 0u); | |
| 165 | |
| 166 // Construct the underlying value using every single key other than those | |
| 167 // on the restricted list.. We can use the same value for every key because we | |
| 168 // validate only by checking the presence of the keys. | |
| 169 DictionaryValue* value = new DictionaryValue(); | |
| 170 for (std::set<std::string>::iterator i = extension_keys.begin(); | |
| 171 i != extension_keys.end(); ++i) | |
| 172 value->Set(*i, Value::CreateStringValue(default_value_)); | |
| 173 | |
| 174 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
| 175 std::string error; | |
| 176 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
| 177 EXPECT_EQ("", error); | |
| 178 AssertType(manifest.get(), Manifest::kTypeExtension); | |
| 179 | |
| 180 // Verify that all the extension keys are accessible. | |
| 181 for (std::set<std::string>::iterator i = extension_keys.begin(); | |
| 182 i != extension_keys.end(); ++i) { | |
| 183 std::string value; | |
| 184 manifest->GetString(*i, &value); | |
| 185 EXPECT_EQ(default_value_, value) << *i; | |
| 186 } | |
| 187 | |
| 188 // Test DeepCopy and Equals. | |
| 189 scoped_ptr<Manifest> manifest2(manifest->DeepCopy()); | |
| 190 EXPECT_TRUE(manifest->Equals(manifest2.get())); | |
| 191 EXPECT_TRUE(manifest2->Equals(manifest.get())); | |
| 192 value->Set("foo", Value::CreateStringValue("blah")); | |
| 193 EXPECT_FALSE(manifest->Equals(manifest2.get())); | |
| 194 } | |
| 195 | |
| 196 // Verifies that themes can access the right keys. | |
| 197 TEST_F(ManifestTest, Theme) { | |
| 198 std::set<std::string> theme_keys = | |
| 199 GetAccessibleKeys(kNotThemeKeys, ARRAYSIZE_UNSAFE(kNotThemeKeys)); | |
| 200 | |
| 201 DictionaryValue* value = new DictionaryValue(); | |
| 202 for (std::set<std::string>::iterator i = theme_keys.begin(); | |
| 203 i != theme_keys.end(); ++i) | |
| 204 value->Set(*i, Value::CreateStringValue(default_value_)); | |
| 205 | |
| 206 std::string theme_key = keys::kTheme + std::string(".test"); | |
| 207 value->Set(theme_key, Value::CreateStringValue(default_value_)); | |
| 208 | |
| 209 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
| 210 std::string error; | |
| 211 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
| 212 EXPECT_EQ("", error); | |
| 213 AssertType(manifest.get(), Manifest::kTypeTheme); | |
| 214 | |
| 215 // Verify that all the theme keys are accessible. | |
| 216 std::string str; | |
| 217 for (std::set<std::string>::iterator i = theme_keys.begin(); | |
| 218 i != theme_keys.end(); ++i) { | |
| 219 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
| 220 EXPECT_EQ(default_value_, str) << *i; | |
| 221 } | |
| 222 EXPECT_TRUE(manifest->GetString(theme_key, &str)); | |
| 223 EXPECT_EQ(default_value_, str) << theme_key; | |
| 224 | |
| 225 // And that all the other keys fail validation and are filtered out | |
| 226 TestRestrictedKeys(manifest.get(), kNotThemeKeys, | |
| 227 ARRAYSIZE_UNSAFE(kNotThemeKeys)); | |
| 228 }; | |
| 229 | |
| 230 // Verifies that platform apps can access the right keys. | |
| 231 TEST_F(ManifestTest, PlatformApp) { | |
| 232 std::set<std::string> platform_keys = GetAccessibleKeys( | |
| 233 kNotPlatformAppKeys, | |
| 234 ARRAYSIZE_UNSAFE(kNotPlatformAppKeys)); | |
| 235 | |
| 236 DictionaryValue* value = new DictionaryValue(); | |
| 237 for (std::set<std::string>::iterator i = platform_keys.begin(); | |
| 238 i != platform_keys.end(); ++i) | |
| 239 value->Set(*i, Value::CreateStringValue(default_value_)); | |
| 240 | |
| 241 value->Set(keys::kPlatformApp, Value::CreateBooleanValue(true)); | |
| 242 | |
| 243 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
| 244 std::string error; | |
| 245 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
| 246 EXPECT_EQ("", error); | |
| 247 AssertType(manifest.get(), Manifest::kTypePlatformApp); | |
| 248 | |
| 249 // Verify that all the platform app keys are accessible. | |
| 250 std::string str; | |
| 251 for (std::set<std::string>::iterator i = platform_keys.begin(); | |
| 252 i != platform_keys.end(); ++i) { | |
| 253 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
| 254 EXPECT_EQ(default_value_, str) << *i; | |
| 255 } | |
| 256 bool is_platform_app = false; | |
| 257 EXPECT_TRUE(manifest->GetBoolean(keys::kPlatformApp, &is_platform_app)); | |
| 258 EXPECT_TRUE(is_platform_app) << keys::kPlatformApp; | |
| 259 | |
| 260 // And that all the other keys fail validation and are filtered out. | |
| 261 TestRestrictedKeys(manifest.get(), kNotPlatformAppKeys, | |
| 262 ARRAYSIZE_UNSAFE(kNotPlatformAppKeys)); | |
| 263 }; | |
| 264 | |
| 265 // Verifies that hosted apps can access the right keys. | |
| 266 TEST_F(ManifestTest, HostedApp) { | |
| 267 std::set<std::string> keys = GetAccessibleKeys( | |
| 268 kNotHostedAppKeys, | |
| 269 ARRAYSIZE_UNSAFE(kNotHostedAppKeys)); | |
| 270 | |
| 271 DictionaryValue* value = new DictionaryValue(); | |
| 272 for (std::set<std::string>::iterator i = keys.begin(); | |
| 273 i != keys.end(); ++i) | |
| 274 value->Set(*i, Value::CreateStringValue(default_value_)); | |
| 275 | |
| 276 value->Set(keys::kWebURLs, Value::CreateStringValue(default_value_)); | |
| 277 | |
| 278 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
| 279 std::string error; | |
| 280 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
| 281 EXPECT_EQ("", error); | |
| 282 AssertType(manifest.get(), Manifest::kTypeHostedApp); | |
| 283 | |
| 284 // Verify that all the hosted app keys are accessible. | |
| 285 std::string str; | |
| 286 for (std::set<std::string>::iterator i = keys.begin(); | |
| 287 i != keys.end(); ++i) { | |
| 288 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
| 289 EXPECT_EQ(default_value_, str) << *i; | |
| 290 } | |
| 291 EXPECT_TRUE(manifest->GetString(keys::kWebURLs, &str)); | |
| 292 EXPECT_EQ(default_value_, str) << keys::kWebURLs; | |
| 293 | |
| 294 // And that all the other keys fail validation and are filtered out. | |
| 295 TestRestrictedKeys(manifest.get(), kNotHostedAppKeys, | |
| 296 ARRAYSIZE_UNSAFE(kNotHostedAppKeys)); | |
| 297 }; | |
| 298 | |
| 299 // Verifies that packaged apps can access the right keys. | |
| 300 TEST_F(ManifestTest, PackagedApp) { | |
| 301 std::set<std::string> keys = GetAccessibleKeys( | |
| 302 kNotPackagedAppKeys, | |
| 303 ARRAYSIZE_UNSAFE(kNotPackagedAppKeys)); | |
| 304 | |
| 305 DictionaryValue* value = new DictionaryValue(); | |
| 306 for (std::set<std::string>::iterator i = keys.begin(); | |
| 307 i != keys.end(); ++i) | |
| 308 value->Set(*i, Value::CreateStringValue(default_value_)); | |
| 309 value->Set(keys::kApp, Value::CreateStringValue(default_value_)); | |
| 310 | |
| 311 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
| 312 std::string error; | |
| 313 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
| 314 EXPECT_EQ("", error); | |
| 315 AssertType(manifest.get(), Manifest::kTypePackagedApp); | |
| 316 | |
| 317 // Verify that all the packaged app keys are accessible. | |
| 318 std::string str; | |
| 319 for (std::set<std::string>::iterator i = keys.begin(); | |
| 320 i != keys.end(); ++i) { | |
| 321 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
| 322 EXPECT_EQ(default_value_, str) << *i; | |
| 323 } | |
| 324 EXPECT_TRUE(manifest->GetString(keys::kApp, &str)); | |
| 325 EXPECT_EQ(default_value_, str) << keys::kApp; | |
| 326 | |
| 327 // And that all the other keys fail validation and are filtered out. | |
| 328 TestRestrictedKeys(manifest.get(), kNotPackagedAppKeys, | |
| 329 ARRAYSIZE_UNSAFE(kNotPackagedAppKeys)); | |
| 330 }; | |
| 331 | |
| 332 // Verifies that the various getters filter unknown and restricted keys. | |
| 333 TEST_F(ManifestTest, Getters) { | |
| 334 DictionaryValue* value = new DictionaryValue(); | |
| 335 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
| 336 std::string unknown_key = "asdfaskldjf"; | |
| 337 | |
| 338 // Verify that the key filtering works for each of the getters. | |
| 339 // Get and GetBoolean | |
| 340 bool expected_bool = true, actual_bool = false; | |
| 341 value->Set(unknown_key, Value::CreateBooleanValue(expected_bool)); | |
| 342 EXPECT_FALSE(manifest->HasKey(unknown_key)); | |
| 343 EXPECT_FALSE(manifest->GetBoolean(unknown_key, &actual_bool)); | |
| 344 EXPECT_FALSE(actual_bool); | |
| 345 Value* actual_value = NULL; | |
| 346 EXPECT_FALSE(manifest->Get(unknown_key, &actual_value)); | |
| 347 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
| 348 | |
| 349 // GetInteger | |
| 350 int expected_int = 5, actual_int = 0; | |
| 351 value->Set(unknown_key, Value::CreateIntegerValue(expected_int)); | |
| 352 EXPECT_FALSE(manifest->GetInteger(unknown_key, &actual_int)); | |
| 353 EXPECT_NE(expected_int, actual_int); | |
| 354 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
| 355 | |
| 356 // GetString | |
| 357 std::string expected_str = "hello", actual_str; | |
| 358 value->Set(unknown_key, Value::CreateStringValue(expected_str)); | |
| 359 EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str)); | |
| 360 EXPECT_NE(expected_str, actual_str); | |
| 361 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
| 362 | |
| 363 // GetString (string16) | |
| 364 string16 expected_str16(UTF8ToUTF16("hello")), actual_str16; | |
| 365 value->Set(unknown_key, Value::CreateStringValue(expected_str16)); | |
| 366 EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str16)); | |
| 367 EXPECT_NE(expected_str16, actual_str16); | |
| 368 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
| 369 | |
| 370 // GetDictionary | |
| 371 DictionaryValue* expected_dict = new DictionaryValue(); | |
| 372 DictionaryValue* actual_dict = NULL; | |
| 373 expected_dict->Set("foo", Value::CreateStringValue("bar")); | |
| 374 value->Set(unknown_key, expected_dict); | |
| 375 EXPECT_FALSE(manifest->GetDictionary(unknown_key, &actual_dict)); | |
| 376 EXPECT_EQ(NULL, actual_dict); | |
| 377 std::string path = unknown_key + ".foo"; | |
| 378 EXPECT_FALSE(manifest->GetString(path, &actual_str)); | |
| 379 EXPECT_NE("bar", actual_str); | |
| 380 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
| 381 | |
| 382 // GetList | |
| 383 ListValue* expected_list = new ListValue(); | |
| 384 ListValue* actual_list = NULL; | |
| 385 expected_list->Append(Value::CreateStringValue("blah")); | |
| 386 value->Set(unknown_key, expected_list); | |
| 387 EXPECT_FALSE(manifest->GetList(unknown_key, &actual_list)); | |
| 388 EXPECT_EQ(NULL, actual_list); | |
| 389 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
| 390 } | |
| 391 | |
| 392 } // namespace extensions | |
| OLD | NEW |