Home | History | Annotate | Download | only in extensions
      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