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/extension.h" 6 7 #if defined(TOOLKIT_GTK) 8 #include <gtk/gtk.h> 9 #endif 10 11 #include "base/format_macros.h" 12 #include "base/file_path.h" 13 #include "base/file_util.h" 14 #include "base/i18n/rtl.h" 15 #include "base/path_service.h" 16 #include "base/string_number_conversions.h" 17 #include "base/string_util.h" 18 #include "base/utf_string_conversions.h" 19 #include "chrome/common/chrome_paths.h" 20 #include "chrome/common/extensions/extension_action.h" 21 #include "chrome/common/extensions/extension_constants.h" 22 #include "chrome/common/extensions/extension_error_utils.h" 23 #include "chrome/common/extensions/extension_resource.h" 24 #include "chrome/common/url_constants.h" 25 #include "content/common/json_value_serializer.h" 26 #include "googleurl/src/gurl.h" 27 #include "net/base/mime_sniffer.h" 28 #include "skia/ext/image_operations.h" 29 #include "chrome/test/ui_test_utils.h" 30 #include "net/base/mock_host_resolver.h" 31 #include "testing/gtest/include/gtest/gtest.h" 32 #include "third_party/skia/include/core/SkBitmap.h" 33 #include "ui/base/l10n/l10n_util.h" 34 #include "ui/gfx/codec/png_codec.h" 35 36 namespace keys = extension_manifest_keys; 37 namespace values = extension_manifest_values; 38 namespace errors = extension_manifest_errors; 39 40 namespace { 41 42 void CompareLists(const std::vector<std::string>& expected, 43 const std::vector<std::string>& actual) { 44 ASSERT_EQ(expected.size(), actual.size()); 45 46 for (size_t i = 0; i < expected.size(); ++i) { 47 EXPECT_EQ(expected[i], actual[i]); 48 } 49 } 50 51 static void AddPattern(ExtensionExtent* extent, const std::string& pattern) { 52 int schemes = URLPattern::SCHEME_ALL; 53 extent->AddPattern(URLPattern(schemes, pattern)); 54 } 55 56 } 57 58 class ExtensionTest : public testing::Test { 59 }; 60 61 // We persist location values in the preferences, so this is a sanity test that 62 // someone doesn't accidentally change them. 63 TEST(ExtensionTest, LocationValuesTest) { 64 ASSERT_EQ(0, Extension::INVALID); 65 ASSERT_EQ(1, Extension::INTERNAL); 66 ASSERT_EQ(2, Extension::EXTERNAL_PREF); 67 ASSERT_EQ(3, Extension::EXTERNAL_REGISTRY); 68 ASSERT_EQ(4, Extension::LOAD); 69 ASSERT_EQ(5, Extension::COMPONENT); 70 ASSERT_EQ(6, Extension::EXTERNAL_PREF_DOWNLOAD); 71 ASSERT_EQ(7, Extension::EXTERNAL_POLICY_DOWNLOAD); 72 } 73 74 TEST(ExtensionTest, LocationPriorityTest) { 75 for (int i = 0; i < Extension::NUM_LOCATIONS; i++) { 76 Extension::Location loc = static_cast<Extension::Location>(i); 77 78 // INVALID is not a valid location. 79 if (loc == Extension::INVALID) 80 continue; 81 82 // Comparing a location that has no rank will hit a CHECK. Do a 83 // compare with every valid location, to be sure each one is covered. 84 85 // Check that no install source can override a componenet extension. 86 ASSERT_EQ(Extension::COMPONENT, 87 Extension::GetHigherPriorityLocation(Extension::COMPONENT, loc)); 88 ASSERT_EQ(Extension::COMPONENT, 89 Extension::GetHigherPriorityLocation(loc, Extension::COMPONENT)); 90 91 // Check that any source can override a user install. This might change 92 // in the future, in which case this test should be updated. 93 ASSERT_EQ(loc, 94 Extension::GetHigherPriorityLocation(Extension::INTERNAL, loc)); 95 ASSERT_EQ(loc, 96 Extension::GetHigherPriorityLocation(loc, Extension::INTERNAL)); 97 } 98 99 // Check a few interesting cases that we know can happen: 100 ASSERT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, 101 Extension::GetHigherPriorityLocation( 102 Extension::EXTERNAL_POLICY_DOWNLOAD, 103 Extension::EXTERNAL_PREF)); 104 105 ASSERT_EQ(Extension::EXTERNAL_PREF, 106 Extension::GetHigherPriorityLocation( 107 Extension::INTERNAL, 108 Extension::EXTERNAL_PREF)); 109 } 110 111 112 // Please don't put any more manifest tests here!! 113 // Move them to extension_manifest_unittest.cc instead and make them use the 114 // more data-driven style there instead. 115 // Bug: http://crbug.com/38462 116 117 118 TEST(ExtensionTest, InitFromValueInvalid) { 119 #if defined(OS_WIN) 120 FilePath path(FILE_PATH_LITERAL("c:\\foo")); 121 #elif defined(OS_POSIX) 122 FilePath path(FILE_PATH_LITERAL("/foo")); 123 #endif 124 scoped_refptr<Extension> extension_ptr(new Extension(path, 125 Extension::INVALID)); 126 Extension& extension = *extension_ptr; 127 int error_code = 0; 128 std::string error; 129 130 // Start with a valid extension manifest 131 FilePath extensions_path; 132 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 133 extensions_path = extensions_path.AppendASCII("extensions") 134 .AppendASCII("good") 135 .AppendASCII("Extensions") 136 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 137 .AppendASCII("1.0.0.0") 138 .Append(Extension::kManifestFilename); 139 140 JSONFileValueSerializer serializer(extensions_path); 141 scoped_ptr<DictionaryValue> valid_value( 142 static_cast<DictionaryValue*>(serializer.Deserialize(&error_code, 143 &error))); 144 EXPECT_EQ("", error); 145 EXPECT_EQ(0, error_code); 146 ASSERT_TRUE(valid_value.get()); 147 ASSERT_TRUE(extension.InitFromValue(*valid_value, Extension::REQUIRE_KEY, 148 &error)); 149 ASSERT_EQ("", error); 150 EXPECT_EQ("en_US", extension.default_locale()); 151 152 scoped_ptr<DictionaryValue> input_value; 153 154 // Test missing and invalid versions 155 input_value.reset(valid_value->DeepCopy()); 156 input_value->Remove(keys::kVersion, NULL); 157 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 158 &error)); 159 EXPECT_EQ(errors::kInvalidVersion, error); 160 161 input_value->SetInteger(keys::kVersion, 42); 162 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 163 &error)); 164 EXPECT_EQ(errors::kInvalidVersion, error); 165 166 // Test missing and invalid names. 167 input_value.reset(valid_value->DeepCopy()); 168 input_value->Remove(keys::kName, NULL); 169 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 170 &error)); 171 EXPECT_EQ(errors::kInvalidName, error); 172 173 input_value->SetInteger(keys::kName, 42); 174 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 175 &error)); 176 EXPECT_EQ(errors::kInvalidName, error); 177 178 // Test invalid description 179 input_value.reset(valid_value->DeepCopy()); 180 input_value->SetInteger(keys::kDescription, 42); 181 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 182 &error)); 183 EXPECT_EQ(errors::kInvalidDescription, error); 184 185 // Test invalid icons 186 input_value.reset(valid_value->DeepCopy()); 187 input_value->SetInteger(keys::kIcons, 42); 188 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 189 &error)); 190 EXPECT_EQ(errors::kInvalidIcons, error); 191 192 // Test invalid icon paths 193 input_value.reset(valid_value->DeepCopy()); 194 DictionaryValue* icons = NULL; 195 input_value->GetDictionary(keys::kIcons, &icons); 196 ASSERT_FALSE(NULL == icons); 197 icons->SetInteger(base::IntToString(128), 42); 198 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 199 &error)); 200 EXPECT_TRUE(MatchPattern(error, errors::kInvalidIconPath)); 201 202 // Test invalid user scripts list 203 input_value.reset(valid_value->DeepCopy()); 204 input_value->SetInteger(keys::kContentScripts, 42); 205 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 206 &error)); 207 EXPECT_EQ(errors::kInvalidContentScriptsList, error); 208 209 // Test invalid user script item 210 input_value.reset(valid_value->DeepCopy()); 211 ListValue* content_scripts = NULL; 212 input_value->GetList(keys::kContentScripts, &content_scripts); 213 ASSERT_FALSE(NULL == content_scripts); 214 content_scripts->Set(0, Value::CreateIntegerValue(42)); 215 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 216 &error)); 217 EXPECT_TRUE(MatchPattern(error, errors::kInvalidContentScript)); 218 219 // Test missing and invalid matches array 220 input_value.reset(valid_value->DeepCopy()); 221 input_value->GetList(keys::kContentScripts, &content_scripts); 222 DictionaryValue* user_script = NULL; 223 content_scripts->GetDictionary(0, &user_script); 224 user_script->Remove(keys::kMatches, NULL); 225 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 226 &error)); 227 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches)); 228 229 user_script->Set(keys::kMatches, Value::CreateIntegerValue(42)); 230 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 231 &error)); 232 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches)); 233 234 ListValue* matches = new ListValue; 235 user_script->Set(keys::kMatches, matches); 236 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 237 &error)); 238 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatchCount)); 239 240 // Test invalid match element 241 matches->Set(0, Value::CreateIntegerValue(42)); 242 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 243 &error)); 244 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch)); 245 246 matches->Set(0, Value::CreateStringValue("chrome://*/*")); 247 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 248 &error)); 249 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch)); 250 251 // Test missing and invalid files array 252 input_value.reset(valid_value->DeepCopy()); 253 input_value->GetList(keys::kContentScripts, &content_scripts); 254 content_scripts->GetDictionary(0, &user_script); 255 user_script->Remove(keys::kJs, NULL); 256 user_script->Remove(keys::kCss, NULL); 257 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 258 &error)); 259 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile)); 260 261 user_script->Set(keys::kJs, Value::CreateIntegerValue(42)); 262 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 263 &error)); 264 EXPECT_TRUE(MatchPattern(error, errors::kInvalidJsList)); 265 266 user_script->Set(keys::kCss, new ListValue); 267 user_script->Set(keys::kJs, new ListValue); 268 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 269 &error)); 270 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile)); 271 user_script->Remove(keys::kCss, NULL); 272 273 ListValue* files = new ListValue; 274 user_script->Set(keys::kJs, files); 275 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 276 &error)); 277 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile)); 278 279 // Test invalid file element 280 files->Set(0, Value::CreateIntegerValue(42)); 281 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 282 &error)); 283 EXPECT_TRUE(MatchPattern(error, errors::kInvalidJs)); 284 285 user_script->Remove(keys::kJs, NULL); 286 // Test the css element 287 user_script->Set(keys::kCss, Value::CreateIntegerValue(42)); 288 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 289 &error)); 290 EXPECT_TRUE(MatchPattern(error, errors::kInvalidCssList)); 291 292 // Test invalid file element 293 ListValue* css_files = new ListValue; 294 user_script->Set(keys::kCss, css_files); 295 css_files->Set(0, Value::CreateIntegerValue(42)); 296 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 297 &error)); 298 EXPECT_TRUE(MatchPattern(error, errors::kInvalidCss)); 299 300 // Test missing and invalid permissions array 301 input_value.reset(valid_value->DeepCopy()); 302 EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 303 &error)); 304 305 ListValue* permissions = NULL; 306 input_value->GetList(keys::kPermissions, &permissions); 307 ASSERT_FALSE(NULL == permissions); 308 309 permissions = new ListValue; 310 input_value->Set(keys::kPermissions, permissions); 311 EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 312 &error)); 313 314 input_value->Set(keys::kPermissions, Value::CreateIntegerValue(9)); 315 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 316 &error)); 317 EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermissions)); 318 319 input_value.reset(valid_value->DeepCopy()); 320 input_value->GetList(keys::kPermissions, &permissions); 321 permissions->Set(0, Value::CreateIntegerValue(24)); 322 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 323 &error)); 324 EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermission)); 325 326 // We allow unknown API permissions, so this will be valid until we better 327 // distinguish between API and host permissions. 328 permissions->Set(0, Value::CreateStringValue("www.google.com")); 329 EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 330 &error)); 331 332 // Multiple page actions are not allowed. 333 input_value.reset(valid_value->DeepCopy()); 334 DictionaryValue* action = new DictionaryValue; 335 action->SetString(keys::kPageActionId, "MyExtensionActionId"); 336 action->SetString(keys::kName, "MyExtensionActionName"); 337 ListValue* action_list = new ListValue; 338 action_list->Append(action->DeepCopy()); 339 action_list->Append(action); 340 input_value->Set(keys::kPageActions, action_list); 341 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 342 &error)); 343 EXPECT_STREQ(errors::kInvalidPageActionsListSize, error.c_str()); 344 345 // Test invalid options page url. 346 input_value.reset(valid_value->DeepCopy()); 347 input_value->Set(keys::kOptionsPage, Value::CreateNullValue()); 348 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 349 &error)); 350 EXPECT_TRUE(MatchPattern(error, errors::kInvalidOptionsPage)); 351 352 // Test invalid/empty default locale. 353 input_value.reset(valid_value->DeepCopy()); 354 input_value->Set(keys::kDefaultLocale, Value::CreateIntegerValue(5)); 355 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 356 &error)); 357 EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale)); 358 359 input_value->Set(keys::kDefaultLocale, Value::CreateStringValue("")); 360 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 361 &error)); 362 EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale)); 363 364 // Test invalid minimum_chrome_version. 365 input_value.reset(valid_value->DeepCopy()); 366 input_value->Set(keys::kMinimumChromeVersion, Value::CreateIntegerValue(42)); 367 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 368 &error)); 369 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMinimumChromeVersion)); 370 371 #if !defined(OS_MACOSX) 372 // TODO(aa): The version isn't stamped into the unit test binary on mac. 373 input_value->Set(keys::kMinimumChromeVersion, 374 Value::CreateStringValue("88.8")); 375 EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY, 376 &error)); 377 EXPECT_TRUE(MatchPattern(error, errors::kChromeVersionTooLow)); 378 #endif 379 } 380 381 TEST(ExtensionTest, InitFromValueValid) { 382 #if defined(OS_WIN) 383 FilePath path(FILE_PATH_LITERAL("C:\\foo")); 384 #elif defined(OS_POSIX) 385 FilePath path(FILE_PATH_LITERAL("/foo")); 386 #endif 387 scoped_refptr<Extension> extension_ptr(new Extension(path, 388 Extension::INVALID)); 389 Extension& extension = *extension_ptr; 390 std::string error; 391 DictionaryValue input_value; 392 393 // Test minimal extension 394 input_value.SetString(keys::kVersion, "1.0.0.0"); 395 input_value.SetString(keys::kName, "my extension"); 396 397 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 398 &error)); 399 EXPECT_EQ("", error); 400 EXPECT_TRUE(Extension::IdIsValid(extension.id())); 401 EXPECT_EQ("1.0.0.0", extension.VersionString()); 402 EXPECT_EQ("my extension", extension.name()); 403 EXPECT_EQ(extension.id(), extension.url().host()); 404 EXPECT_EQ(path.value(), extension.path().value()); 405 406 // Test permissions scheme. 407 ListValue* permissions = new ListValue; 408 permissions->Set(0, Value::CreateStringValue("file:///C:/foo.txt")); 409 input_value.Set(keys::kPermissions, permissions); 410 411 // We allow unknown API permissions, so this will be valid until we better 412 // distinguish between API and host permissions. 413 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 414 &error)); 415 input_value.Remove(keys::kPermissions, NULL); 416 417 // Test with an options page. 418 input_value.SetString(keys::kOptionsPage, "options.html"); 419 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 420 &error)); 421 EXPECT_EQ("", error); 422 EXPECT_EQ("chrome-extension", extension.options_url().scheme()); 423 EXPECT_EQ("/options.html", extension.options_url().path()); 424 425 // Test that an empty list of page actions does not stop a browser action 426 // from being loaded. 427 ListValue* empty_list = new ListValue; 428 input_value.Set(keys::kPageActions, empty_list); 429 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 430 &error)); 431 EXPECT_EQ("", error); 432 433 #if !defined(OS_MACOSX) 434 // TODO(aa): The version isn't stamped into the unit test binary on mac. 435 // Test with a minimum_chrome_version. 436 input_value.SetString(keys::kMinimumChromeVersion, "1.0"); 437 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 438 &error)); 439 EXPECT_EQ("", error); 440 // The minimum chrome version is not stored in the Extension object. 441 #endif 442 } 443 444 TEST(ExtensionTest, InitFromValueValidNameInRTL) { 445 #if defined(TOOLKIT_GTK) 446 GtkTextDirection gtk_dir = gtk_widget_get_default_direction(); 447 gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL); 448 #else 449 std::string locale = l10n_util::GetApplicationLocale(""); 450 base::i18n::SetICUDefaultLocale("he"); 451 #endif 452 453 #if defined(OS_WIN) 454 FilePath path(FILE_PATH_LITERAL("C:\\foo")); 455 #elif defined(OS_POSIX) 456 FilePath path(FILE_PATH_LITERAL("/foo")); 457 #endif 458 scoped_refptr<Extension> extension_ptr(new Extension(path, 459 Extension::INVALID)); 460 Extension& extension = *extension_ptr; 461 std::string error; 462 DictionaryValue input_value; 463 464 input_value.SetString(keys::kVersion, "1.0.0.0"); 465 // No strong RTL characters in name. 466 std::wstring name(L"Dictionary (by Google)"); 467 input_value.SetString(keys::kName, WideToUTF16Hack(name)); 468 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 469 &error)); 470 EXPECT_EQ("", error); 471 std::wstring localized_name(name); 472 base::i18n::AdjustStringForLocaleDirection(&localized_name); 473 EXPECT_EQ(localized_name, UTF8ToWide(extension.name())); 474 475 // Strong RTL characters in name. 476 name = L"Dictionary (\x05D1\x05D2"L" Google)"; 477 input_value.SetString(keys::kName, WideToUTF16Hack(name)); 478 EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS, 479 &error)); 480 EXPECT_EQ("", error); 481 localized_name = name; 482 base::i18n::AdjustStringForLocaleDirection(&localized_name); 483 EXPECT_EQ(localized_name, UTF8ToWide(extension.name())); 484 485 // Reset locale. 486 #if defined(TOOLKIT_GTK) 487 gtk_widget_set_default_direction(gtk_dir); 488 #else 489 base::i18n::SetICUDefaultLocale(locale); 490 #endif 491 } 492 493 TEST(ExtensionTest, GetResourceURLAndPath) { 494 #if defined(OS_WIN) 495 FilePath path(FILE_PATH_LITERAL("C:\\foo")); 496 #elif defined(OS_POSIX) 497 FilePath path(FILE_PATH_LITERAL("/foo")); 498 #endif 499 DictionaryValue input_value; 500 input_value.SetString(keys::kVersion, "1.0.0.0"); 501 input_value.SetString(keys::kName, "my extension"); 502 scoped_refptr<Extension> extension(Extension::Create(path, 503 Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS, NULL)); 504 EXPECT_TRUE(extension.get()); 505 506 EXPECT_EQ(extension->url().spec() + "bar/baz.js", 507 Extension::GetResourceURL(extension->url(), "bar/baz.js").spec()); 508 EXPECT_EQ(extension->url().spec() + "baz.js", 509 Extension::GetResourceURL(extension->url(), 510 "bar/../baz.js").spec()); 511 EXPECT_EQ(extension->url().spec() + "baz.js", 512 Extension::GetResourceURL(extension->url(), "../baz.js").spec()); 513 } 514 515 TEST(ExtensionTest, LoadPageActionHelper) { 516 #if defined(OS_WIN) 517 FilePath path(base::StringPrintf(L"c:\\extension")); 518 #else 519 FilePath path(base::StringPrintf("/extension")); 520 #endif 521 scoped_refptr<Extension> extension_ptr(new Extension(path, 522 Extension::INVALID)); 523 Extension& extension = *extension_ptr; 524 std::string error_msg; 525 scoped_ptr<ExtensionAction> action; 526 DictionaryValue input; 527 528 // First try with an empty dictionary. 529 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 530 ASSERT_TRUE(action != NULL); 531 ASSERT_TRUE(error_msg.empty()); 532 533 // Now setup some values to use in the action. 534 const std::string id("MyExtensionActionId"); 535 const std::string name("MyExtensionActionName"); 536 std::string img1("image1.png"); 537 std::string img2("image2.png"); 538 539 // Add the dictionary for the contextual action. 540 input.SetString(keys::kPageActionId, id); 541 input.SetString(keys::kName, name); 542 ListValue* icons = new ListValue; 543 icons->Set(0, Value::CreateStringValue(img1)); 544 icons->Set(1, Value::CreateStringValue(img2)); 545 input.Set(keys::kPageActionIcons, icons); 546 547 // Parse and read back the values from the object. 548 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 549 ASSERT_TRUE(NULL != action.get()); 550 ASSERT_TRUE(error_msg.empty()); 551 ASSERT_EQ(id, action->id()); 552 // No title, so fall back to name. 553 ASSERT_EQ(name, action->GetTitle(1)); 554 ASSERT_EQ(2u, action->icon_paths()->size()); 555 ASSERT_EQ(img1, (*action->icon_paths())[0]); 556 ASSERT_EQ(img2, (*action->icon_paths())[1]); 557 558 // Explicitly set the same type and parse again. 559 input.SetString(keys::kType, values::kPageActionTypeTab); 560 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 561 ASSERT_TRUE(NULL != action.get()); 562 ASSERT_TRUE(error_msg.empty()); 563 564 // Make a deep copy of the input and remove one key at a time and see if we 565 // get the right error. 566 scoped_ptr<DictionaryValue> copy; 567 568 // First remove id key. 569 copy.reset(input.DeepCopy()); 570 copy->Remove(keys::kPageActionId, NULL); 571 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg)); 572 ASSERT_TRUE(NULL != action.get()); 573 574 // Then remove the name key. It's optional, so no error. 575 copy.reset(input.DeepCopy()); 576 copy->Remove(keys::kName, NULL); 577 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg)); 578 ASSERT_TRUE(NULL != action.get()); 579 ASSERT_TRUE(action->GetTitle(1).empty()); 580 ASSERT_TRUE(error_msg.empty()); 581 582 // Then remove the icon paths key. 583 copy.reset(input.DeepCopy()); 584 copy->Remove(keys::kPageActionIcons, NULL); 585 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg)); 586 ASSERT_TRUE(NULL != action.get()); 587 error_msg = ""; 588 589 // Now test that we can parse the new format for page actions. 590 591 // Now setup some values to use in the page action. 592 const std::string kTitle("MyExtensionActionTitle"); 593 const std::string kIcon("image1.png"); 594 const std::string kPopupHtmlFile("a_popup.html"); 595 596 // Add the dictionary for the contextual action. 597 input.Clear(); 598 input.SetString(keys::kPageActionDefaultTitle, kTitle); 599 input.SetString(keys::kPageActionDefaultIcon, kIcon); 600 601 // Parse and read back the values from the object. 602 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 603 ASSERT_TRUE(action.get()); 604 ASSERT_TRUE(error_msg.empty()); 605 ASSERT_EQ(kTitle, action->GetTitle(1)); 606 ASSERT_EQ(0u, action->icon_paths()->size()); 607 608 // Invalid title should give an error even with a valid name. 609 input.Clear(); 610 input.SetInteger(keys::kPageActionDefaultTitle, 42); 611 input.SetString(keys::kName, name); 612 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 613 ASSERT_TRUE(NULL == action.get()); 614 ASSERT_STREQ(errors::kInvalidPageActionDefaultTitle, error_msg.c_str()); 615 error_msg = ""; 616 617 // Invalid name should give an error only with no title. 618 input.SetString(keys::kPageActionDefaultTitle, kTitle); 619 input.SetInteger(keys::kName, 123); 620 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 621 ASSERT_TRUE(NULL != action.get()); 622 ASSERT_EQ(kTitle, action->GetTitle(1)); 623 ASSERT_TRUE(error_msg.empty()); 624 625 input.Remove(keys::kPageActionDefaultTitle, NULL); 626 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 627 ASSERT_TRUE(NULL == action.get()); 628 ASSERT_STREQ(errors::kInvalidPageActionName, error_msg.c_str()); 629 error_msg = ""; 630 631 // Test that keys "popup" and "default_popup" both work, but can not 632 // be used at the same time. 633 input.Clear(); 634 input.SetString(keys::kPageActionDefaultTitle, kTitle); 635 input.SetString(keys::kPageActionDefaultIcon, kIcon); 636 637 // LoadExtensionActionHelper expects the extension member |extension_url| 638 // to be set. 639 extension.extension_url_ = 640 GURL(std::string(chrome::kExtensionScheme) + 641 chrome::kStandardSchemeSeparator + 642 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"); 643 644 // Add key "popup", expect success. 645 input.SetString(keys::kPageActionPopup, kPopupHtmlFile); 646 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 647 ASSERT_TRUE(NULL != action.get()); 648 ASSERT_TRUE(error_msg.empty()); 649 ASSERT_STREQ( 650 extension.url().Resolve(kPopupHtmlFile).spec().c_str(), 651 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 652 653 // Add key "default_popup", expect failure. 654 input.SetString(keys::kPageActionDefaultPopup, kPopupHtmlFile); 655 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 656 ASSERT_TRUE(NULL == action.get()); 657 ASSERT_STREQ( 658 ExtensionErrorUtils::FormatErrorMessage( 659 errors::kInvalidPageActionOldAndNewKeys, 660 keys::kPageActionDefaultPopup, 661 keys::kPageActionPopup).c_str(), 662 error_msg.c_str()); 663 error_msg = ""; 664 665 // Remove key "popup", expect success. 666 input.Remove(keys::kPageActionPopup, NULL); 667 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 668 ASSERT_TRUE(NULL != action.get()); 669 ASSERT_TRUE(error_msg.empty()); 670 ASSERT_STREQ( 671 extension.url().Resolve(kPopupHtmlFile).spec().c_str(), 672 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 673 674 // Setting default_popup to "" is the same as having no popup. 675 input.Remove(keys::kPageActionDefaultPopup, NULL); 676 input.SetString(keys::kPageActionDefaultPopup, ""); 677 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 678 ASSERT_TRUE(NULL != action.get()); 679 ASSERT_TRUE(error_msg.empty()); 680 EXPECT_FALSE(action->HasPopup(ExtensionAction::kDefaultTabId)); 681 ASSERT_STREQ( 682 "", 683 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 684 685 // Setting popup to "" is the same as having no popup. 686 input.Remove(keys::kPageActionDefaultPopup, NULL); 687 input.SetString(keys::kPageActionPopup, ""); 688 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 689 ASSERT_TRUE(NULL != action.get()); 690 ASSERT_TRUE(error_msg.empty()); 691 EXPECT_FALSE(action->HasPopup(ExtensionAction::kDefaultTabId)); 692 ASSERT_STREQ( 693 "", 694 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 695 } 696 697 TEST(ExtensionTest, IdIsValid) { 698 EXPECT_TRUE(Extension::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); 699 EXPECT_TRUE(Extension::IdIsValid("pppppppppppppppppppppppppppppppp")); 700 EXPECT_TRUE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnop")); 701 EXPECT_TRUE(Extension::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")); 702 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno")); 703 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnopa")); 704 EXPECT_FALSE(Extension::IdIsValid("0123456789abcdef0123456789abcdef")); 705 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnoq")); 706 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno0")); 707 } 708 709 TEST(ExtensionTest, GenerateID) { 710 const uint8 public_key_info[] = { 711 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 712 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 713 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 714 0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 715 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 716 0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 717 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 718 0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 719 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 720 0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 721 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 722 0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 723 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 724 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01 725 }; 726 727 std::string extension_id; 728 EXPECT_TRUE( 729 Extension::GenerateId( 730 std::string(reinterpret_cast<const char*>(&public_key_info[0]), 731 arraysize(public_key_info)), 732 &extension_id)); 733 EXPECT_EQ("melddjfinppjdikinhbgehiennejpfhp", extension_id); 734 } 735 736 TEST(ExtensionTest, UpdateUrls) { 737 // Test several valid update urls 738 std::vector<std::string> valid; 739 valid.push_back("http://test.com"); 740 valid.push_back("http://test.com/"); 741 valid.push_back("http://test.com/update"); 742 valid.push_back("http://test.com/update?check=true"); 743 for (size_t i = 0; i < valid.size(); i++) { 744 GURL url(valid[i]); 745 EXPECT_TRUE(url.is_valid()); 746 747 DictionaryValue input_value; 748 #if defined(OS_WIN) 749 // (Why %Iu below? This is the single file in the whole code base that 750 // might make use of a WidePRIuS; let's not encourage any more.) 751 FilePath path(base::StringPrintf(L"c:\\extension%Iu", i)); 752 #else 753 FilePath path(base::StringPrintf("/extension%" PRIuS, i)); 754 #endif 755 std::string error; 756 757 input_value.SetString(keys::kVersion, "1.0"); 758 input_value.SetString(keys::kName, "Test"); 759 input_value.SetString(keys::kUpdateURL, url.spec()); 760 761 scoped_refptr<Extension> extension(Extension::Create( 762 path, Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS, 763 &error)); 764 EXPECT_TRUE(extension.get()) << error; 765 } 766 767 // Test some invalid update urls 768 std::vector<std::string> invalid; 769 invalid.push_back(""); 770 invalid.push_back("test.com"); 771 valid.push_back("http://test.com/update#whatever"); 772 for (size_t i = 0; i < invalid.size(); i++) { 773 DictionaryValue input_value; 774 #if defined(OS_WIN) 775 // (Why %Iu below? This is the single file in the whole code base that 776 // might make use of a WidePRIuS; let's not encourage any more.) 777 FilePath path(base::StringPrintf(L"c:\\extension%Iu", i)); 778 #else 779 FilePath path(base::StringPrintf("/extension%" PRIuS, i)); 780 #endif 781 std::string error; 782 input_value.SetString(keys::kVersion, "1.0"); 783 input_value.SetString(keys::kName, "Test"); 784 input_value.SetString(keys::kUpdateURL, invalid[i]); 785 786 scoped_refptr<Extension> extension(Extension::Create( 787 path, Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS, 788 &error)); 789 EXPECT_FALSE(extension.get()); 790 EXPECT_TRUE(MatchPattern(error, errors::kInvalidUpdateURL)); 791 } 792 } 793 794 // This test ensures that the mimetype sniffing code stays in sync with the 795 // actual crx files that we test other parts of the system with. 796 TEST(ExtensionTest, MimeTypeSniffing) { 797 FilePath path; 798 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 799 path = path.AppendASCII("extensions").AppendASCII("good.crx"); 800 801 std::string data; 802 ASSERT_TRUE(file_util::ReadFileToString(path, &data)); 803 804 std::string result; 805 EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(), 806 GURL("http://www.example.com/foo.crx"), "", &result)); 807 EXPECT_EQ(std::string(Extension::kMimeType), result); 808 809 data.clear(); 810 result.clear(); 811 path = path.DirName().AppendASCII("bad_magic.crx"); 812 ASSERT_TRUE(file_util::ReadFileToString(path, &data)); 813 EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(), 814 GURL("http://www.example.com/foo.crx"), "", &result)); 815 EXPECT_EQ("application/octet-stream", result); 816 } 817 818 static scoped_refptr<Extension> LoadManifest(const std::string& dir, 819 const std::string& test_file, 820 int extra_flags) { 821 FilePath path; 822 PathService::Get(chrome::DIR_TEST_DATA, &path); 823 path = path.AppendASCII("extensions") 824 .AppendASCII(dir) 825 .AppendASCII(test_file); 826 827 JSONFileValueSerializer serializer(path); 828 std::string error; 829 scoped_ptr<Value> result(serializer.Deserialize(NULL, &error)); 830 if (!result.get()) { 831 EXPECT_EQ("", error); 832 return NULL; 833 } 834 835 scoped_refptr<Extension> extension = Extension::Create( 836 path.DirName(), Extension::INVALID, 837 *static_cast<DictionaryValue*>(result.get()), 838 Extension::STRICT_ERROR_CHECKS | extra_flags, &error); 839 EXPECT_TRUE(extension) << error; 840 return extension; 841 } 842 843 static scoped_refptr<Extension> LoadManifest(const std::string& dir, 844 const std::string& test_file) { 845 return LoadManifest(dir, test_file, Extension::NO_FLAGS); 846 } 847 848 TEST(ExtensionTest, EffectiveHostPermissions) { 849 scoped_refptr<Extension> extension; 850 ExtensionExtent hosts; 851 852 extension = LoadManifest("effective_host_permissions", "empty.json"); 853 EXPECT_EQ(0u, extension->GetEffectiveHostPermissions().patterns().size()); 854 EXPECT_FALSE(hosts.ContainsURL(GURL("http://www.google.com"))); 855 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 856 857 extension = LoadManifest("effective_host_permissions", "one_host.json"); 858 hosts = extension->GetEffectiveHostPermissions(); 859 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 860 EXPECT_FALSE(hosts.ContainsURL(GURL("https://www.google.com"))); 861 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 862 863 extension = LoadManifest("effective_host_permissions", 864 "one_host_wildcard.json"); 865 hosts = extension->GetEffectiveHostPermissions(); 866 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com"))); 867 EXPECT_TRUE(hosts.ContainsURL(GURL("http://foo.google.com"))); 868 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 869 870 extension = LoadManifest("effective_host_permissions", "two_hosts.json"); 871 hosts = extension->GetEffectiveHostPermissions(); 872 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 873 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.reddit.com"))); 874 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 875 876 extension = LoadManifest("effective_host_permissions", 877 "https_not_considered.json"); 878 hosts = extension->GetEffectiveHostPermissions(); 879 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com"))); 880 EXPECT_TRUE(hosts.ContainsURL(GURL("https://google.com"))); 881 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 882 883 extension = LoadManifest("effective_host_permissions", 884 "two_content_scripts.json"); 885 hosts = extension->GetEffectiveHostPermissions(); 886 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com"))); 887 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.reddit.com"))); 888 EXPECT_TRUE(hosts.ContainsURL(GURL("http://news.ycombinator.com"))); 889 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 890 891 extension = LoadManifest("effective_host_permissions", "all_hosts.json"); 892 hosts = extension->GetEffectiveHostPermissions(); 893 EXPECT_TRUE(hosts.ContainsURL(GURL("http://test/"))); 894 EXPECT_FALSE(hosts.ContainsURL(GURL("https://test/"))); 895 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 896 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts()); 897 898 extension = LoadManifest("effective_host_permissions", "all_hosts2.json"); 899 hosts = extension->GetEffectiveHostPermissions(); 900 EXPECT_TRUE(hosts.ContainsURL(GURL("http://test/"))); 901 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 902 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts()); 903 904 extension = LoadManifest("effective_host_permissions", "all_hosts3.json"); 905 hosts = extension->GetEffectiveHostPermissions(); 906 EXPECT_FALSE(hosts.ContainsURL(GURL("http://test/"))); 907 EXPECT_TRUE(hosts.ContainsURL(GURL("https://test/"))); 908 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 909 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts()); 910 } 911 912 TEST(ExtensionTest, IsPrivilegeIncrease) { 913 const struct { 914 const char* base_name; 915 // Increase these sizes if you have more than 10. 916 const char* granted_apis[10]; 917 const char* granted_hosts[10]; 918 bool full_access; 919 bool expect_increase; 920 } kTests[] = { 921 { "allhosts1", {NULL}, {"http://*/", NULL}, false, 922 false }, // all -> all 923 { "allhosts2", {NULL}, {"http://*/", NULL}, false, 924 false }, // all -> one 925 { "allhosts3", {NULL}, {NULL}, false, true }, // one -> all 926 { "hosts1", {NULL}, 927 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false, 928 false }, // http://a,http://b -> http://a,http://b 929 { "hosts2", {NULL}, 930 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false, 931 true }, // http://a,http://b -> https://a,http://*.b 932 { "hosts3", {NULL}, 933 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false, 934 false }, // http://a,http://b -> http://a 935 { "hosts4", {NULL}, 936 {"http://www.google.com/", NULL}, false, 937 true }, // http://a -> http://a,http://b 938 { "hosts5", {"tabs", "notifications", NULL}, 939 {"http://*.example.com/", "http://*.example.com/*", 940 "http://*.example.co.uk/*", "http://*.example.com.au/*", 941 NULL}, false, 942 false }, // http://a,b,c -> http://a,b,c + https://a,b,c 943 { "hosts6", {"tabs", "notifications", NULL}, 944 {"http://*.example.com/", "http://*.example.com/*", NULL}, false, 945 false }, // http://a.com -> http://a.com + http://a.co.uk 946 { "permissions1", {"tabs", NULL}, 947 {NULL}, false, false }, // tabs -> tabs 948 { "permissions2", {"tabs", NULL}, 949 {NULL}, false, true }, // tabs -> tabs,bookmarks 950 { "permissions3", {NULL}, 951 {"http://*/*", NULL}, 952 false, true }, // http://a -> http://a,tabs 953 { "permissions5", {"bookmarks", NULL}, 954 {NULL}, false, true }, // bookmarks -> bookmarks,history 955 #if !defined(OS_CHROMEOS) // plugins aren't allowed in ChromeOS 956 { "permissions4", {NULL}, 957 {NULL}, true, false }, // plugin -> plugin,tabs 958 { "plugin1", {NULL}, 959 {NULL}, true, false }, // plugin -> plugin 960 { "plugin2", {NULL}, 961 {NULL}, true, false }, // plugin -> none 962 { "plugin3", {NULL}, 963 {NULL}, false, true }, // none -> plugin 964 #endif 965 { "storage", {NULL}, 966 {NULL}, false, false }, // none -> storage 967 { "notifications", {NULL}, 968 {NULL}, false, false } // none -> notifications 969 }; 970 971 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) { 972 scoped_refptr<Extension> old_extension( 973 LoadManifest("allow_silent_upgrade", 974 std::string(kTests[i].base_name) + "_old.json")); 975 scoped_refptr<Extension> new_extension( 976 LoadManifest("allow_silent_upgrade", 977 std::string(kTests[i].base_name) + "_new.json")); 978 979 std::set<std::string> granted_apis; 980 for (size_t j = 0; kTests[i].granted_apis[j] != NULL; ++j) 981 granted_apis.insert(kTests[i].granted_apis[j]); 982 983 ExtensionExtent granted_hosts; 984 for (size_t j = 0; kTests[i].granted_hosts[j] != NULL; ++j) 985 AddPattern(&granted_hosts, kTests[i].granted_hosts[j]); 986 987 EXPECT_TRUE(new_extension.get()) << kTests[i].base_name << "_new.json"; 988 if (!new_extension.get()) 989 continue; 990 991 EXPECT_EQ(kTests[i].expect_increase, 992 Extension::IsPrivilegeIncrease(kTests[i].full_access, 993 granted_apis, 994 granted_hosts, 995 new_extension.get())) 996 << kTests[i].base_name; 997 } 998 } 999 1000 TEST(ExtensionTest, PermissionMessages) { 1001 // Ensure that all permissions that needs to show install UI actually have 1002 // strings associated with them. 1003 1004 std::set<std::string> skip; 1005 1006 // These are considered "nuisance" or "trivial" permissions that don't need 1007 // a prompt. 1008 skip.insert(Extension::kContextMenusPermission); 1009 skip.insert(Extension::kIdlePermission); 1010 skip.insert(Extension::kNotificationPermission); 1011 skip.insert(Extension::kUnlimitedStoragePermission); 1012 skip.insert(Extension::kContentSettingsPermission); 1013 1014 // TODO(erikkay) add a string for this permission. 1015 skip.insert(Extension::kBackgroundPermission); 1016 1017 // The cookie permission does nothing unless you have associated host 1018 // permissions. 1019 skip.insert(Extension::kCookiePermission); 1020 1021 // The proxy permission is warned as part of host permission checks. 1022 skip.insert(Extension::kProxyPermission); 1023 1024 // This permission requires explicit user action (context menu handler) 1025 // so we won't prompt for it for now. 1026 skip.insert(Extension::kFileBrowserHandlerPermission); 1027 1028 // If you've turned on the experimental command-line flag, we don't need 1029 // to warn you further. 1030 skip.insert(Extension::kExperimentalPermission); 1031 1032 // These are only usable by component extensions. 1033 skip.insert(Extension::kWebstorePrivatePermission); 1034 skip.insert(Extension::kFileBrowserPrivatePermission); 1035 skip.insert(Extension::kChromeosInfoPrivatePermissions); 1036 1037 const Extension::PermissionMessage::MessageId ID_NONE = 1038 Extension::PermissionMessage::ID_NONE; 1039 1040 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { 1041 Extension::Permission permission = Extension::kPermissions[i]; 1042 if (skip.count(permission.name)) { 1043 EXPECT_EQ(ID_NONE, permission.message_id) 1044 << "unexpected message_id for " << permission.name; 1045 } else { 1046 EXPECT_NE(ID_NONE, permission.message_id) 1047 << "missing message_id for " << permission.name; 1048 } 1049 } 1050 } 1051 1052 // Returns a copy of |source| resized to |size| x |size|. 1053 static SkBitmap ResizedCopy(const SkBitmap& source, int size) { 1054 return skia::ImageOperations::Resize(source, 1055 skia::ImageOperations::RESIZE_LANCZOS3, 1056 size, 1057 size); 1058 } 1059 1060 static bool SizeEquals(const SkBitmap& bitmap, const gfx::Size& size) { 1061 return bitmap.width() == size.width() && bitmap.height() == size.height(); 1062 } 1063 1064 TEST(ExtensionTest, ImageCaching) { 1065 FilePath path; 1066 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 1067 path = path.AppendASCII("extensions"); 1068 1069 // Initialize the Extension. 1070 std::string errors; 1071 DictionaryValue values; 1072 values.SetString(keys::kName, "test"); 1073 values.SetString(keys::kVersion, "0.1"); 1074 scoped_refptr<Extension> extension(Extension::Create( 1075 path, Extension::INVALID, values, Extension::STRICT_ERROR_CHECKS, 1076 &errors)); 1077 ASSERT_TRUE(extension.get()); 1078 1079 // Create an ExtensionResource pointing at an icon. 1080 FilePath icon_relative_path(FILE_PATH_LITERAL("icon3.png")); 1081 ExtensionResource resource(extension->id(), 1082 extension->path(), 1083 icon_relative_path); 1084 1085 // Read in the icon file. 1086 FilePath icon_absolute_path = extension->path().Append(icon_relative_path); 1087 std::string raw_png; 1088 ASSERT_TRUE(file_util::ReadFileToString(icon_absolute_path, &raw_png)); 1089 SkBitmap image; 1090 ASSERT_TRUE(gfx::PNGCodec::Decode( 1091 reinterpret_cast<const unsigned char*>(raw_png.data()), 1092 raw_png.length(), 1093 &image)); 1094 1095 // Make sure the icon file is the size we expect. 1096 gfx::Size original_size(66, 66); 1097 ASSERT_EQ(image.width(), original_size.width()); 1098 ASSERT_EQ(image.height(), original_size.height()); 1099 1100 // Create two resized versions at size 16x16 and 24x24. 1101 SkBitmap image16 = ResizedCopy(image, 16); 1102 SkBitmap image24 = ResizedCopy(image, 24); 1103 1104 gfx::Size size16(16, 16); 1105 gfx::Size size24(24, 24); 1106 1107 // Cache the 16x16 copy. 1108 EXPECT_FALSE(extension->HasCachedImage(resource, size16)); 1109 extension->SetCachedImage(resource, image16, original_size); 1110 EXPECT_TRUE(extension->HasCachedImage(resource, size16)); 1111 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size16), size16)); 1112 EXPECT_FALSE(extension->HasCachedImage(resource, size24)); 1113 EXPECT_FALSE(extension->HasCachedImage(resource, original_size)); 1114 1115 // Cache the 24x24 copy. 1116 extension->SetCachedImage(resource, image24, original_size); 1117 EXPECT_TRUE(extension->HasCachedImage(resource, size24)); 1118 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size24), size24)); 1119 EXPECT_FALSE(extension->HasCachedImage(resource, original_size)); 1120 1121 // Cache the original, and verify that it gets returned when we ask for a 1122 // max_size that is larger than the original. 1123 gfx::Size size128(128, 128); 1124 EXPECT_TRUE(image.width() < size128.width() && 1125 image.height() < size128.height()); 1126 extension->SetCachedImage(resource, image, original_size); 1127 EXPECT_TRUE(extension->HasCachedImage(resource, original_size)); 1128 EXPECT_TRUE(extension->HasCachedImage(resource, size128)); 1129 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, original_size), 1130 original_size)); 1131 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size128), 1132 original_size)); 1133 EXPECT_EQ(extension->GetCachedImage(resource, original_size).getPixels(), 1134 extension->GetCachedImage(resource, size128).getPixels()); 1135 } 1136 1137 // Tests that the old permission name "unlimited_storage" still works for 1138 // backwards compatibility (we renamed it to "unlimitedStorage"). 1139 TEST(ExtensionTest, OldUnlimitedStoragePermission) { 1140 ScopedTempDir directory; 1141 ASSERT_TRUE(directory.CreateUniqueTempDir()); 1142 FilePath extension_path = directory.path(); 1143 DictionaryValue dictionary; 1144 1145 // The two required keys. 1146 dictionary.SetString(extension_manifest_keys::kName, "test"); 1147 dictionary.SetString(extension_manifest_keys::kVersion, "0.1"); 1148 1149 // Create a permissions list containing "unlimited_storage" and add it. 1150 ListValue* permissions = new ListValue(); 1151 const char* old_unlimited = "unlimited_storage"; 1152 EXPECT_STREQ(old_unlimited, Extension::kOldUnlimitedStoragePermission); 1153 permissions->Append(Value::CreateStringValue(old_unlimited)); 1154 dictionary.Set(extension_manifest_keys::kPermissions, permissions); 1155 1156 // Initialize the extension and make sure the permission for unlimited storage 1157 // is present. 1158 std::string errors; 1159 scoped_refptr<Extension> extension(Extension::Create( 1160 extension_path, Extension::INVALID, dictionary, 1161 Extension::STRICT_ERROR_CHECKS, &errors)); 1162 EXPECT_TRUE(extension.get()); 1163 EXPECT_TRUE(extension->HasApiPermission( 1164 Extension::kUnlimitedStoragePermission)); 1165 } 1166 1167 // This tests the API permissions with an empty manifest (one that just 1168 // specifies a name and a version and nothing else). 1169 TEST(ExtensionTest, ApiPermissions) { 1170 const struct { 1171 const char* permission_name; 1172 bool expect_success; 1173 } kTests[] = { 1174 // Negative test. 1175 { "non_existing_permission", false }, 1176 // Test default module/package permission. 1177 { "browserAction", true }, 1178 { "browserActions", true }, 1179 { "devtools", true }, 1180 { "extension", true }, 1181 { "i18n", true }, 1182 { "pageAction", true }, 1183 { "pageActions", true }, 1184 { "test", true }, 1185 // Some negative tests. 1186 { "bookmarks", false }, 1187 { "cookies", false }, 1188 { "history", false }, 1189 { "tabs.onUpdated", false }, 1190 // Make sure we find the module name after stripping '.' and '/'. 1191 { "browserAction/abcd/onClick", true }, 1192 { "browserAction.abcd.onClick", true }, 1193 // Test Tabs functions. 1194 { "tabs.create", true}, 1195 { "tabs.update", true}, 1196 { "tabs.getSelected", false}, 1197 }; 1198 1199 scoped_refptr<Extension> extension; 1200 extension = LoadManifest("empty_manifest", "empty.json"); 1201 1202 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) { 1203 EXPECT_EQ(kTests[i].expect_success, 1204 extension->HasApiPermission(kTests[i].permission_name)) 1205 << "Permission being tested: " << kTests[i].permission_name; 1206 } 1207 } 1208 1209 TEST(ExtensionTest, GetHostPermissionMessages_ManyHosts) { 1210 scoped_refptr<Extension> extension; 1211 extension = LoadManifest("permissions", "many-hosts.json"); 1212 std::vector<string16> warnings = extension->GetPermissionMessageStrings(); 1213 ASSERT_EQ(1u, warnings.size()); 1214 EXPECT_EQ("Your data on www.google.com and encrypted.google.com", 1215 UTF16ToUTF8(warnings[0])); 1216 } 1217 1218 TEST(ExtensionTest, GetPermissionMessages_Plugins) { 1219 scoped_refptr<Extension> extension; 1220 extension = LoadManifest("permissions", "plugins.json"); 1221 std::vector<string16> warnings = extension->GetPermissionMessageStrings(); 1222 // We don't parse the plugins key on Chrome OS, so it should not ask for any 1223 // permissions. 1224 #if defined(OS_CHROMEOS) 1225 ASSERT_EQ(0u, warnings.size()); 1226 #else 1227 ASSERT_EQ(1u, warnings.size()); 1228 EXPECT_EQ("All data on your computer and the websites you visit", 1229 UTF16ToUTF8(warnings[0])); 1230 #endif 1231 } 1232 1233 TEST(ExtensionTest, WantsFileAccess) { 1234 scoped_refptr<Extension> extension; 1235 GURL file_url("file:///etc/passwd"); 1236 1237 // <all_urls> permission 1238 extension = LoadManifest("permissions", "permissions_all_urls.json"); 1239 EXPECT_TRUE(extension->wants_file_access()); 1240 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL)); 1241 extension = LoadManifest( 1242 "permissions", "permissions_all_urls.json", Extension::ALLOW_FILE_ACCESS); 1243 EXPECT_TRUE(extension->wants_file_access()); 1244 EXPECT_TRUE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL)); 1245 1246 // file:///* permission 1247 extension = LoadManifest("permissions", "permissions_file_scheme.json"); 1248 EXPECT_TRUE(extension->wants_file_access()); 1249 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL)); 1250 extension = LoadManifest("permissions", "permissions_file_scheme.json", 1251 Extension::ALLOW_FILE_ACCESS); 1252 EXPECT_TRUE(extension->wants_file_access()); 1253 EXPECT_TRUE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL)); 1254 1255 // http://* permission 1256 extension = LoadManifest("permissions", "permissions_http_scheme.json"); 1257 EXPECT_FALSE(extension->wants_file_access()); 1258 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL)); 1259 extension = LoadManifest("permissions", "permissions_http_scheme.json", 1260 Extension::ALLOW_FILE_ACCESS); 1261 EXPECT_FALSE(extension->wants_file_access()); 1262 EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL)); 1263 1264 // <all_urls> content script match 1265 extension = LoadManifest("permissions", "content_script_all_urls.json"); 1266 EXPECT_TRUE(extension->wants_file_access()); 1267 EXPECT_FALSE(extension->CanExecuteScriptOnPage( 1268 file_url, &extension->content_scripts()[0], NULL)); 1269 extension = LoadManifest("permissions", "content_script_all_urls.json", 1270 Extension::ALLOW_FILE_ACCESS); 1271 EXPECT_TRUE(extension->wants_file_access()); 1272 EXPECT_TRUE(extension->CanExecuteScriptOnPage( 1273 file_url, &extension->content_scripts()[0], NULL)); 1274 1275 // file:///* content script match 1276 extension = LoadManifest("permissions", "content_script_file_scheme.json"); 1277 EXPECT_TRUE(extension->wants_file_access()); 1278 EXPECT_FALSE(extension->CanExecuteScriptOnPage( 1279 file_url, &extension->content_scripts()[0], NULL)); 1280 extension = LoadManifest("permissions", "content_script_file_scheme.json", 1281 Extension::ALLOW_FILE_ACCESS); 1282 EXPECT_TRUE(extension->wants_file_access()); 1283 EXPECT_TRUE(extension->CanExecuteScriptOnPage( 1284 file_url, &extension->content_scripts()[0], NULL)); 1285 1286 // http://* content script match 1287 extension = LoadManifest("permissions", "content_script_http_scheme.json"); 1288 EXPECT_FALSE(extension->wants_file_access()); 1289 EXPECT_FALSE(extension->CanExecuteScriptOnPage( 1290 file_url, &extension->content_scripts()[0], NULL)); 1291 extension = LoadManifest("permissions", "content_script_http_scheme.json", 1292 Extension::ALLOW_FILE_ACCESS); 1293 EXPECT_FALSE(extension->wants_file_access()); 1294 EXPECT_FALSE(extension->CanExecuteScriptOnPage( 1295 file_url, &extension->content_scripts()[0], NULL)); 1296 } 1297 1298 // Base class for testing the CanExecuteScriptOnPage and CanCaptureVisiblePage 1299 // methods of Extension for extensions with various permissions. 1300 class ExtensionScriptAndCaptureVisibleTest : public testing::Test { 1301 public: 1302 ExtensionScriptAndCaptureVisibleTest() { 1303 PathService::Get(chrome::DIR_TEST_DATA, &dirpath_); 1304 } 1305 1306 scoped_refptr<Extension> MakeExtension(const std::string& permissions, 1307 Extension::Location location) { 1308 // Replace single-quotes with double-quotes in permissions, since JSON 1309 // mandates double-quotes. 1310 std::string munged_permissions = permissions; 1311 ReplaceSubstringsAfterOffset(&munged_permissions, 0, "'", "\""); 1312 1313 DictionaryValue dictionary; 1314 dictionary.SetString(keys::kName, "permission test"); 1315 dictionary.SetString(keys::kVersion, "1"); 1316 std::string error; 1317 JSONStringValueSerializer serializer(munged_permissions); 1318 scoped_ptr<Value> permission_value(serializer.Deserialize(NULL, &error)); 1319 EXPECT_EQ("", error); 1320 if (!permission_value.get()) 1321 return NULL; 1322 EXPECT_TRUE(permission_value->IsType(Value::TYPE_LIST)); 1323 dictionary.Set(keys::kPermissions, permission_value.release()); 1324 1325 FilePath dirpath; 1326 PathService::Get(chrome::DIR_TEST_DATA, &dirpath); 1327 dirpath = dirpath.AppendASCII("extensions").AppendASCII("permissions"); 1328 1329 scoped_refptr<Extension> extension = Extension::Create( 1330 dirpath, 1331 location, 1332 dictionary, 1333 Extension::STRICT_ERROR_CHECKS, 1334 &error); 1335 if (!extension) 1336 VLOG(1) << error; 1337 return extension; 1338 } 1339 1340 bool Allowed(const Extension* extension, const GURL& url) { 1341 return (extension->CanExecuteScriptOnPage(url, NULL, NULL) && 1342 extension->CanCaptureVisiblePage(url, NULL)); 1343 } 1344 1345 bool CaptureOnly(const Extension* extension, const GURL& url) { 1346 return !extension->CanExecuteScriptOnPage(url, NULL, NULL) && 1347 extension->CanCaptureVisiblePage(url, NULL); 1348 } 1349 1350 bool Blocked(const Extension* extension, const GURL& url) { 1351 return !(extension->CanExecuteScriptOnPage(url, NULL, NULL) || 1352 extension->CanCaptureVisiblePage(url, NULL)); 1353 } 1354 1355 protected: 1356 FilePath dirpath_; 1357 }; 1358 1359 TEST_F(ExtensionScriptAndCaptureVisibleTest, Permissions) { 1360 scoped_refptr<Extension> extension; 1361 // URLs that are "safe" to provide scripting and capture visible tab access 1362 // to if the permissions allow it. 1363 GURL http_url("http://www.google.com"); 1364 GURL https_url("https://www.google.com"); 1365 GURL file_url("file:///foo/bar"); 1366 1367 // We should allow host permission but not scripting permission for favicon 1368 // urls. 1369 GURL favicon_url("chrome://favicon/http://www.google.com"); 1370 1371 std::string dummy_id = 1372 Extension::GenerateIdForPath(FilePath(FILE_PATH_LITERAL("whatever"))); 1373 1374 // URLs that regular extensions should never get access to. 1375 GURL extension_url("chrome-extension://" + dummy_id); 1376 GURL settings_url("chrome://settings"); 1377 GURL about_url("about:flags"); 1378 1379 // Test <all_urls> for regular extensions. 1380 extension = MakeExtension("['tabs','<all_urls>']", Extension::INTERNAL); 1381 EXPECT_TRUE(Allowed(extension, http_url)); 1382 EXPECT_TRUE(Allowed(extension, https_url)); 1383 EXPECT_TRUE(Blocked(extension, file_url)); 1384 EXPECT_TRUE(Blocked(extension, settings_url)); 1385 EXPECT_TRUE(CaptureOnly(extension, favicon_url)); 1386 EXPECT_TRUE(Blocked(extension, about_url)); 1387 EXPECT_TRUE(Blocked(extension, extension_url)); 1388 1389 EXPECT_FALSE(extension->HasHostPermission(settings_url)); 1390 EXPECT_FALSE(extension->HasHostPermission(about_url)); 1391 EXPECT_TRUE(extension->HasHostPermission(favicon_url)); 1392 1393 // Test * for scheme, which implies just the http/https schemes. 1394 extension = MakeExtension("['tabs','*://*/']", Extension::INTERNAL); 1395 EXPECT_TRUE(Allowed(extension, http_url)); 1396 EXPECT_TRUE(Allowed(extension, https_url)); 1397 EXPECT_TRUE(Blocked(extension, settings_url)); 1398 EXPECT_TRUE(Blocked(extension, about_url)); 1399 EXPECT_TRUE(Blocked(extension, file_url)); 1400 EXPECT_TRUE(Blocked(extension, favicon_url)); 1401 extension = MakeExtension("['tabs','*://settings/*']", Extension::INTERNAL); 1402 EXPECT_TRUE(Blocked(extension, settings_url)); 1403 1404 // Having chrome://*/ should not work for regular extensions. Note that 1405 // for favicon access, we require the explicit pattern chrome://favicon/*. 1406 extension = MakeExtension("['tabs','chrome://*/']", 1407 Extension::INTERNAL); 1408 EXPECT_TRUE(extension == NULL); 1409 1410 // Having chrome://favicon/* should not give you chrome://* 1411 extension = MakeExtension("['tabs','chrome://favicon/*']", 1412 Extension::INTERNAL); 1413 EXPECT_TRUE(Blocked(extension, settings_url)); 1414 EXPECT_TRUE(CaptureOnly(extension, favicon_url)); 1415 EXPECT_TRUE(Blocked(extension, about_url)); 1416 EXPECT_TRUE(extension->HasHostPermission(favicon_url)); 1417 1418 // Having http://favicon should not give you chrome://favicon 1419 extension = MakeExtension("['tabs', 'http://favicon/']", Extension::INTERNAL); 1420 EXPECT_TRUE(Blocked(extension, settings_url)); 1421 EXPECT_TRUE(Blocked(extension, favicon_url)); 1422 1423 // Component extensions with <all_urls> should get everything. 1424 extension = MakeExtension("['tabs','<all_urls>']", Extension::COMPONENT); 1425 EXPECT_TRUE(Allowed(extension, http_url)); 1426 EXPECT_TRUE(Allowed(extension, https_url)); 1427 EXPECT_TRUE(Allowed(extension, settings_url)); 1428 EXPECT_TRUE(Allowed(extension, about_url)); 1429 EXPECT_TRUE(Allowed(extension, favicon_url)); 1430 EXPECT_TRUE(extension->HasHostPermission(favicon_url)); 1431 1432 // Component extensions should only get access to what they ask for. 1433 extension = MakeExtension("['tabs', 'http://www.google.com/']", 1434 Extension::COMPONENT); 1435 EXPECT_TRUE(Allowed(extension, http_url)); 1436 EXPECT_TRUE(Blocked(extension, https_url)); 1437 EXPECT_TRUE(Blocked(extension, file_url)); 1438 EXPECT_TRUE(Blocked(extension, settings_url)); 1439 EXPECT_TRUE(Blocked(extension, favicon_url)); 1440 EXPECT_TRUE(Blocked(extension, about_url)); 1441 EXPECT_TRUE(Blocked(extension, extension_url)); 1442 EXPECT_FALSE(extension->HasHostPermission(settings_url)); 1443 } 1444 1445 1446 TEST(ExtensionTest, GetDistinctHostsForDisplay) { 1447 std::vector<std::string> expected; 1448 expected.push_back("www.foo.com"); 1449 expected.push_back("www.bar.com"); 1450 expected.push_back("www.baz.com"); 1451 URLPatternList actual; 1452 1453 { 1454 SCOPED_TRACE("no dupes"); 1455 1456 // Simple list with no dupes. 1457 actual.push_back( 1458 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1459 actual.push_back( 1460 URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/path")); 1461 actual.push_back( 1462 URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path")); 1463 CompareLists(expected, 1464 Extension::GetDistinctHostsForDisplay(actual)); 1465 } 1466 1467 { 1468 SCOPED_TRACE("two dupes"); 1469 1470 // Add some dupes. 1471 actual.push_back( 1472 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1473 actual.push_back( 1474 URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path")); 1475 CompareLists(expected, 1476 Extension::GetDistinctHostsForDisplay(actual)); 1477 } 1478 1479 { 1480 SCOPED_TRACE("schemes differ"); 1481 1482 // Add a pattern that differs only by scheme. This should be filtered out. 1483 actual.push_back( 1484 URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path")); 1485 CompareLists(expected, 1486 Extension::GetDistinctHostsForDisplay(actual)); 1487 } 1488 1489 { 1490 SCOPED_TRACE("paths differ"); 1491 1492 // Add some dupes by path. 1493 actual.push_back( 1494 URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath")); 1495 CompareLists(expected, 1496 Extension::GetDistinctHostsForDisplay(actual)); 1497 } 1498 1499 { 1500 SCOPED_TRACE("subdomains differ"); 1501 1502 // We don't do anything special for subdomains. 1503 actual.push_back( 1504 URLPattern(URLPattern::SCHEME_HTTP, "http://monkey.www.bar.com/path")); 1505 actual.push_back( 1506 URLPattern(URLPattern::SCHEME_HTTP, "http://bar.com/path")); 1507 1508 expected.push_back("monkey.www.bar.com"); 1509 expected.push_back("bar.com"); 1510 1511 CompareLists(expected, 1512 Extension::GetDistinctHostsForDisplay(actual)); 1513 } 1514 1515 { 1516 SCOPED_TRACE("RCDs differ"); 1517 1518 // Now test for RCD uniquing. 1519 actual.push_back( 1520 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1521 actual.push_back( 1522 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path")); 1523 actual.push_back( 1524 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.de/path")); 1525 actual.push_back( 1526 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca.us/path")); 1527 actual.push_back( 1528 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path")); 1529 actual.push_back( 1530 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com.my/path")); 1531 1532 // This is an unknown RCD, which shouldn't be uniqued out. 1533 actual.push_back( 1534 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path")); 1535 // But it should only occur once. 1536 actual.push_back( 1537 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path")); 1538 1539 expected.push_back("www.foo.xyzzy"); 1540 1541 CompareLists(expected, 1542 Extension::GetDistinctHostsForDisplay(actual)); 1543 } 1544 1545 { 1546 SCOPED_TRACE("wildcards"); 1547 1548 actual.push_back( 1549 URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*")); 1550 1551 expected.push_back("*.google.com"); 1552 1553 CompareLists(expected, 1554 Extension::GetDistinctHostsForDisplay(actual)); 1555 } 1556 } 1557 1558 TEST(ExtensionTest, GetDistinctHostsForDisplay_ComIsBestRcd) { 1559 URLPatternList actual; 1560 actual.push_back( 1561 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path")); 1562 actual.push_back( 1563 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path")); 1564 actual.push_back( 1565 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path")); 1566 actual.push_back( 1567 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path")); 1568 actual.push_back( 1569 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path")); 1570 actual.push_back( 1571 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1572 1573 std::vector<std::string> expected; 1574 expected.push_back("www.foo.com"); 1575 1576 CompareLists(expected, 1577 Extension::GetDistinctHostsForDisplay(actual)); 1578 } 1579 1580 TEST(ExtensionTest, GetDistinctHostsForDisplay_NetIs2ndBestRcd) { 1581 URLPatternList actual; 1582 actual.push_back( 1583 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path")); 1584 actual.push_back( 1585 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path")); 1586 actual.push_back( 1587 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path")); 1588 actual.push_back( 1589 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path")); 1590 actual.push_back( 1591 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path")); 1592 // No http://www.foo.com/path 1593 1594 std::vector<std::string> expected; 1595 expected.push_back("www.foo.net"); 1596 1597 CompareLists(expected, 1598 Extension::GetDistinctHostsForDisplay(actual)); 1599 } 1600 1601 TEST(ExtensionTest, GetDistinctHostsForDisplay_OrgIs3rdBestRcd) { 1602 URLPatternList actual; 1603 actual.push_back( 1604 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path")); 1605 actual.push_back( 1606 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path")); 1607 actual.push_back( 1608 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path")); 1609 // No http://www.foo.net/path 1610 actual.push_back( 1611 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path")); 1612 // No http://www.foo.com/path 1613 1614 std::vector<std::string> expected; 1615 expected.push_back("www.foo.org"); 1616 1617 CompareLists(expected, 1618 Extension::GetDistinctHostsForDisplay(actual)); 1619 } 1620 1621 TEST(ExtensionTest, GetDistinctHostsForDisplay_FirstInListIs4thBestRcd) { 1622 URLPatternList actual; 1623 actual.push_back( 1624 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path")); 1625 // No http://www.foo.org/path 1626 actual.push_back( 1627 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path")); 1628 // No http://www.foo.net/path 1629 actual.push_back( 1630 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path")); 1631 // No http://www.foo.com/path 1632 1633 std::vector<std::string> expected; 1634 expected.push_back("www.foo.ca"); 1635 1636 CompareLists(expected, 1637 Extension::GetDistinctHostsForDisplay(actual)); 1638 } 1639 1640 TEST(ExtensionTest, IsElevatedHostList) { 1641 URLPatternList list1; 1642 URLPatternList list2; 1643 1644 list1.push_back( 1645 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path")); 1646 list1.push_back( 1647 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path")); 1648 1649 // Test that the host order does not matter. 1650 list2.push_back( 1651 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path")); 1652 list2.push_back( 1653 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path")); 1654 1655 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2)); 1656 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1657 1658 // Test that paths are ignored. 1659 list2.clear(); 1660 list2.push_back( 1661 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*")); 1662 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2)); 1663 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1664 1665 // Test that RCDs are ignored. 1666 list2.clear(); 1667 list2.push_back( 1668 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*")); 1669 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2)); 1670 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1671 1672 // Test that subdomain wildcards are handled properly. 1673 list2.clear(); 1674 list2.push_back( 1675 URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*")); 1676 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2)); 1677 //TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337 1678 //EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1679 1680 // Test that different domains count as different hosts. 1681 list2.clear(); 1682 list2.push_back( 1683 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path")); 1684 list2.push_back( 1685 URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path")); 1686 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2)); 1687 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1688 1689 // Test that different subdomains count as different hosts. 1690 list2.clear(); 1691 list2.push_back( 1692 URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*")); 1693 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2)); 1694 EXPECT_TRUE(Extension::IsElevatedHostList(list2, list1)); 1695 } 1696 1697 TEST(ExtensionTest, GenerateId) { 1698 std::string result; 1699 EXPECT_TRUE(Extension::GenerateId("", &result)); 1700 1701 EXPECT_TRUE(Extension::GenerateId("test", &result)); 1702 EXPECT_EQ(result, "jpignaibiiemhngfjkcpokkamffknabf"); 1703 1704 EXPECT_TRUE(Extension::GenerateId("_", &result)); 1705 EXPECT_EQ(result, "ncocknphbhhlhkikpnnlmbcnbgdempcd"); 1706 1707 EXPECT_TRUE(Extension::GenerateId( 1708 "this_string_is_longer_than_a_single_sha256_hash_digest", &result)); 1709 EXPECT_EQ(result, "jimneklojkjdibfkgiiophfhjhbdgcfi"); 1710 } 1711