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 #include <algorithm>
      8 
      9 #include "base/base64.h"
     10 #include "base/basictypes.h"
     11 #include "base/command_line.h"
     12 #include "base/file_path.h"
     13 #include "base/file_util.h"
     14 #include "base/i18n/rtl.h"
     15 #include "base/logging.h"
     16 #include "base/memory/singleton.h"
     17 #include "base/stl_util-inl.h"
     18 #include "base/string16.h"
     19 #include "base/string_number_conversions.h"
     20 #include "base/utf_string_conversions.h"
     21 #include "base/values.h"
     22 #include "base/version.h"
     23 #include "crypto/sha2.h"
     24 #include "crypto/third_party/nss/blapi.h"
     25 #include "chrome/common/chrome_constants.h"
     26 #include "chrome/common/chrome_switches.h"
     27 #include "chrome/common/chrome_version_info.h"
     28 #include "chrome/common/extensions/extension_action.h"
     29 #include "chrome/common/extensions/extension_constants.h"
     30 #include "chrome/common/extensions/extension_error_utils.h"
     31 #include "chrome/common/extensions/extension_l10n_util.h"
     32 #include "chrome/common/extensions/extension_resource.h"
     33 #include "chrome/common/extensions/extension_sidebar_defaults.h"
     34 #include "chrome/common/extensions/extension_sidebar_utils.h"
     35 #include "chrome/common/extensions/file_browser_handler.h"
     36 #include "chrome/common/extensions/user_script.h"
     37 #include "chrome/common/url_constants.h"
     38 #include "googleurl/src/url_util.h"
     39 #include "grit/chromium_strings.h"
     40 #include "grit/generated_resources.h"
     41 #include "grit/theme_resources.h"
     42 #include "net/base/registry_controlled_domain.h"
     43 #include "third_party/skia/include/core/SkBitmap.h"
     44 #include "ui/base/l10n/l10n_util.h"
     45 #include "ui/base/resource/resource_bundle.h"
     46 #include "webkit/glue/image_decoder.h"
     47 
     48 namespace keys = extension_manifest_keys;
     49 namespace values = extension_manifest_values;
     50 namespace errors = extension_manifest_errors;
     51 
     52 namespace {
     53 
     54 const int kPEMOutputColumns = 65;
     55 
     56 // KEY MARKERS
     57 const char kKeyBeginHeaderMarker[] = "-----BEGIN";
     58 const char kKeyBeginFooterMarker[] = "-----END";
     59 const char kKeyInfoEndMarker[] = "KEY-----";
     60 const char kPublic[] = "PUBLIC";
     61 const char kPrivate[] = "PRIVATE";
     62 
     63 const int kRSAKeySize = 1024;
     64 
     65 // Converts a normal hexadecimal string into the alphabet used by extensions.
     66 // We use the characters 'a'-'p' instead of '0'-'f' to avoid ever having a
     67 // completely numeric host, since some software interprets that as an IP
     68 // address.
     69 static void ConvertHexadecimalToIDAlphabet(std::string* id) {
     70   for (size_t i = 0; i < id->size(); ++i) {
     71     int val;
     72     if (base::HexStringToInt(id->begin() + i, id->begin() + i + 1, &val))
     73       (*id)[i] = val + 'a';
     74     else
     75       (*id)[i] = 'a';
     76   }
     77 }
     78 
     79 // These keys are allowed by all crx files (apps, extensions, themes, etc).
     80 static const char* kBaseCrxKeys[] = {
     81   keys::kCurrentLocale,
     82   keys::kDefaultLocale,
     83   keys::kDescription,
     84   keys::kIcons,
     85   keys::kName,
     86   keys::kPublicKey,
     87   keys::kSignature,
     88   keys::kVersion,
     89   keys::kUpdateURL
     90 };
     91 
     92 bool IsBaseCrxKey(const std::string& key) {
     93   for (size_t i = 0; i < arraysize(kBaseCrxKeys); ++i) {
     94     if (key == kBaseCrxKeys[i])
     95       return true;
     96   }
     97 
     98   return false;
     99 }
    100 
    101 // Constant used to represent an undefined l10n message id.
    102 const int kUndefinedMessageId = -1;
    103 
    104 // Names of API modules that do not require a permission.
    105 const char kBrowserActionModuleName[] = "browserAction";
    106 const char kBrowserActionsModuleName[] = "browserActions";
    107 const char kDevToolsModuleName[] = "devtools";
    108 const char kExtensionModuleName[] = "extension";
    109 const char kI18NModuleName[] = "i18n";
    110 const char kOmniboxModuleName[] = "omnibox";
    111 const char kPageActionModuleName[] = "pageAction";
    112 const char kPageActionsModuleName[] = "pageActions";
    113 const char kTestModuleName[] = "test";
    114 
    115 // Names of modules that can be used without listing it in the permissions
    116 // section of the manifest.
    117 const char* kNonPermissionModuleNames[] = {
    118   kBrowserActionModuleName,
    119   kBrowserActionsModuleName,
    120   kDevToolsModuleName,
    121   kExtensionModuleName,
    122   kI18NModuleName,
    123   kOmniboxModuleName,
    124   kPageActionModuleName,
    125   kPageActionsModuleName,
    126   kTestModuleName
    127 };
    128 const size_t kNumNonPermissionModuleNames =
    129     arraysize(kNonPermissionModuleNames);
    130 
    131 // Names of functions (within modules requiring permissions) that can be used
    132 // without asking for the module permission. In other words, functions you can
    133 // use with no permissions specified.
    134 const char* kNonPermissionFunctionNames[] = {
    135   "tabs.create",
    136   "tabs.update"
    137 };
    138 const size_t kNumNonPermissionFunctionNames =
    139     arraysize(kNonPermissionFunctionNames);
    140 
    141 // A singleton object containing global data needed by the extension objects.
    142 class ExtensionConfig {
    143  public:
    144   static ExtensionConfig* GetInstance() {
    145     return Singleton<ExtensionConfig>::get();
    146   }
    147 
    148   Extension::PermissionMessage::MessageId GetPermissionMessageId(
    149       const std::string& permission) {
    150     return Extension::kPermissions[permission_map_[permission]].message_id;
    151   }
    152 
    153   Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; }
    154 
    155  private:
    156   friend struct DefaultSingletonTraits<ExtensionConfig>;
    157 
    158   ExtensionConfig() {
    159     for (size_t i = 0; i < Extension::kNumPermissions; ++i)
    160       permission_map_[Extension::kPermissions[i].name] = i;
    161   };
    162 
    163   ~ExtensionConfig() { }
    164 
    165   std::map<const std::string, size_t> permission_map_;
    166 
    167   // A whitelist of extensions that can script anywhere. Do not add to this
    168   // list (except in tests) without consulting the Extensions team first.
    169   // Note: Component extensions have this right implicitly and do not need to be
    170   // added to this list.
    171   Extension::ScriptingWhitelist scripting_whitelist_;
    172 };
    173 
    174 // Aliased to kTabPermission for purposes of API checks, but not allowed
    175 // in the permissions field of the manifest.
    176 static const char kWindowPermission[] = "windows";
    177 
    178 // Rank extension locations in a way that allows
    179 // Extension::GetHigherPriorityLocation() to compare locations.
    180 // An extension installed from two locations will have the location
    181 // with the higher rank, as returned by this function. The actual
    182 // integer values may change, and should never be persisted.
    183 int GetLocationRank(Extension::Location location) {
    184   const int kInvalidRank = -1;
    185   int rank = kInvalidRank;  // Will CHECK that rank is not kInvalidRank.
    186 
    187   switch (location) {
    188     // Component extensions can not be overriden by any other type.
    189     case Extension::COMPONENT:
    190       rank = 6;
    191       break;
    192 
    193     // Policy controlled extensions may not be overridden by any type
    194     // that is not part of chrome.
    195     case Extension::EXTERNAL_POLICY_DOWNLOAD:
    196       rank = 5;
    197       break;
    198 
    199     // A developer-loaded extension should override any installed type
    200     // that a user can disable.
    201     case Extension::LOAD:
    202       rank = 4;
    203       break;
    204 
    205     // The relative priority of various external sources is not important,
    206     // but having some order ensures deterministic behavior.
    207     case Extension::EXTERNAL_REGISTRY:
    208       rank = 3;
    209       break;
    210 
    211     case Extension::EXTERNAL_PREF:
    212       rank = 2;
    213       break;
    214 
    215     case Extension::EXTERNAL_PREF_DOWNLOAD:
    216       rank = 1;
    217       break;
    218 
    219     // User installed extensions are overridden by any external type.
    220     case Extension::INTERNAL:
    221       rank = 0;
    222       break;
    223 
    224     default:
    225       NOTREACHED() << "Need to add new extension locaton " << location;
    226   }
    227 
    228   CHECK(rank != kInvalidRank);
    229   return rank;
    230 }
    231 
    232 }  // namespace
    233 
    234 const FilePath::CharType Extension::kManifestFilename[] =
    235     FILE_PATH_LITERAL("manifest.json");
    236 const FilePath::CharType Extension::kLocaleFolder[] =
    237     FILE_PATH_LITERAL("_locales");
    238 const FilePath::CharType Extension::kMessagesFilename[] =
    239     FILE_PATH_LITERAL("messages.json");
    240 
    241 #if defined(OS_WIN)
    242 const char Extension::kExtensionRegistryPath[] =
    243     "Software\\Google\\Chrome\\Extensions";
    244 #endif
    245 
    246 // first 16 bytes of SHA256 hashed public key.
    247 const size_t Extension::kIdSize = 16;
    248 
    249 const char Extension::kMimeType[] = "application/x-chrome-extension";
    250 
    251 const int Extension::kIconSizes[] = {
    252   EXTENSION_ICON_LARGE,
    253   EXTENSION_ICON_MEDIUM,
    254   EXTENSION_ICON_SMALL,
    255   EXTENSION_ICON_SMALLISH,
    256   EXTENSION_ICON_BITTY
    257 };
    258 
    259 const int Extension::kPageActionIconMaxSize = 19;
    260 const int Extension::kBrowserActionIconMaxSize = 19;
    261 const int Extension::kSidebarIconMaxSize = 16;
    262 
    263 // Explicit permissions -- permission declaration required.
    264 const char Extension::kBackgroundPermission[] = "background";
    265 const char Extension::kBookmarkPermission[] = "bookmarks";
    266 const char Extension::kContextMenusPermission[] = "contextMenus";
    267 const char Extension::kContentSettingsPermission[] = "contentSettings";
    268 const char Extension::kCookiePermission[] = "cookies";
    269 const char Extension::kChromeosInfoPrivatePermissions[] = "chromeosInfoPrivate";
    270 const char Extension::kDebuggerPermission[] = "debugger";
    271 const char Extension::kExperimentalPermission[] = "experimental";
    272 const char Extension::kFileBrowserHandlerPermission[] = "fileBrowserHandler";
    273 const char Extension::kFileBrowserPrivatePermission[] = "fileBrowserPrivate";
    274 const char Extension::kGeolocationPermission[] = "geolocation";
    275 const char Extension::kHistoryPermission[] = "history";
    276 const char Extension::kIdlePermission[] = "idle";
    277 const char Extension::kManagementPermission[] = "management";
    278 const char Extension::kNotificationPermission[] = "notifications";
    279 const char Extension::kProxyPermission[] = "proxy";
    280 const char Extension::kTabPermission[] = "tabs";
    281 const char Extension::kUnlimitedStoragePermission[] = "unlimitedStorage";
    282 const char Extension::kWebstorePrivatePermission[] = "webstorePrivate";
    283 
    284 // In general, all permissions should have an install message.
    285 // See ExtensionsTest.PermissionMessages for an explanation of each
    286 // exception.
    287 const Extension::Permission Extension::kPermissions[] = {
    288   { kBackgroundPermission,           PermissionMessage::ID_NONE },
    289   { kBookmarkPermission,             PermissionMessage::ID_BOOKMARKS },
    290   { kChromeosInfoPrivatePermissions, PermissionMessage::ID_NONE },
    291   { kContentSettingsPermission,      PermissionMessage::ID_NONE },
    292   { kContextMenusPermission,         PermissionMessage::ID_NONE },
    293   { kCookiePermission,               PermissionMessage::ID_NONE },
    294   { kDebuggerPermission,             PermissionMessage::ID_DEBUGGER },
    295   { kExperimentalPermission,         PermissionMessage::ID_NONE },
    296   { kFileBrowserHandlerPermission,   PermissionMessage::ID_NONE },
    297   { kFileBrowserPrivatePermission,   PermissionMessage::ID_NONE },
    298   { kGeolocationPermission,          PermissionMessage::ID_GEOLOCATION },
    299   { kIdlePermission,                 PermissionMessage::ID_NONE },
    300   { kHistoryPermission,              PermissionMessage::ID_BROWSING_HISTORY },
    301   { kManagementPermission,           PermissionMessage::ID_MANAGEMENT },
    302   { kNotificationPermission,         PermissionMessage::ID_NONE },
    303   { kProxyPermission,                PermissionMessage::ID_NONE },
    304   { kTabPermission,                  PermissionMessage::ID_TABS },
    305   { kUnlimitedStoragePermission,     PermissionMessage::ID_NONE },
    306   { kWebstorePrivatePermission,      PermissionMessage::ID_NONE }
    307 };
    308 const size_t Extension::kNumPermissions =
    309     arraysize(Extension::kPermissions);
    310 
    311 const char* const Extension::kHostedAppPermissionNames[] = {
    312   Extension::kBackgroundPermission,
    313   Extension::kGeolocationPermission,
    314   Extension::kNotificationPermission,
    315   Extension::kUnlimitedStoragePermission,
    316   Extension::kWebstorePrivatePermission,
    317 };
    318 const size_t Extension::kNumHostedAppPermissions =
    319     arraysize(Extension::kHostedAppPermissionNames);
    320 
    321 const char* const Extension::kComponentPrivatePermissionNames[] = {
    322     Extension::kFileBrowserPrivatePermission,
    323     Extension::kWebstorePrivatePermission,
    324     Extension::kChromeosInfoPrivatePermissions,
    325 };
    326 const size_t Extension::kNumComponentPrivatePermissions =
    327     arraysize(Extension::kComponentPrivatePermissionNames);
    328 
    329 // We purposefully don't put this into kPermissionNames.
    330 const char Extension::kOldUnlimitedStoragePermission[] = "unlimited_storage";
    331 
    332 const int Extension::kValidWebExtentSchemes =
    333     URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
    334 
    335 const int Extension::kValidHostPermissionSchemes =
    336     UserScript::kValidUserScriptSchemes | URLPattern::SCHEME_CHROMEUI;
    337 
    338 //
    339 // PermissionMessage
    340 //
    341 
    342 // static
    343 Extension::PermissionMessage Extension::PermissionMessage::CreateFromMessageId(
    344     Extension::PermissionMessage::MessageId message_id) {
    345   DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
    346   if (message_id <= ID_NONE)
    347     return PermissionMessage(message_id, string16());
    348 
    349   string16 message = l10n_util::GetStringUTF16(kMessageIds[message_id]);
    350   return PermissionMessage(message_id, message);
    351 }
    352 
    353 // static
    354 Extension::PermissionMessage Extension::PermissionMessage::CreateFromHostList(
    355     const std::vector<std::string> hosts) {
    356   CHECK(hosts.size() > 0);
    357 
    358   MessageId message_id;
    359   string16 message;
    360   switch (hosts.size()) {
    361     case 1:
    362       message_id = ID_HOSTS_1;
    363       message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
    364                                            UTF8ToUTF16(hosts[0]));
    365       break;
    366     case 2:
    367       message_id = ID_HOSTS_2;
    368       message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
    369                                            UTF8ToUTF16(hosts[0]),
    370                                            UTF8ToUTF16(hosts[1]));
    371       break;
    372     case 3:
    373       message_id = ID_HOSTS_3;
    374       message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
    375                                            UTF8ToUTF16(hosts[0]),
    376                                            UTF8ToUTF16(hosts[1]),
    377                                            UTF8ToUTF16(hosts[2]));
    378       break;
    379     default:
    380       message_id = ID_HOSTS_4_OR_MORE;
    381       message = l10n_util::GetStringFUTF16(
    382           kMessageIds[message_id],
    383           UTF8ToUTF16(hosts[0]),
    384           UTF8ToUTF16(hosts[1]),
    385           base::IntToString16(hosts.size() - 2));
    386       break;
    387   }
    388 
    389   return PermissionMessage(message_id, message);
    390 }
    391 
    392 Extension::PermissionMessage::PermissionMessage(
    393     Extension::PermissionMessage::MessageId message_id, string16 message)
    394     : message_id_(message_id),
    395       message_(message) {
    396 }
    397 
    398 const int Extension::PermissionMessage::kMessageIds[] = {
    399   kUndefinedMessageId,  // "unknown"
    400   kUndefinedMessageId,  // "none"
    401   IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
    402   IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION,
    403   IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY,
    404   IDS_EXTENSION_PROMPT_WARNING_TABS,
    405   IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
    406   IDS_EXTENSION_PROMPT_WARNING_DEBUGGER,
    407   IDS_EXTENSION_PROMPT_WARNING_1_HOST,
    408   IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
    409   IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
    410   IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS,
    411   IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
    412   IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS
    413 };
    414 
    415 //
    416 // Extension
    417 //
    418 
    419 // static
    420 scoped_refptr<Extension> Extension::Create(const FilePath& path,
    421                                            Location location,
    422                                            const DictionaryValue& value,
    423                                            int flags,
    424                                            std::string* error) {
    425   scoped_refptr<Extension> extension = new Extension(path, location);
    426 
    427   if (!extension->InitFromValue(value, flags, error))
    428     return NULL;
    429   return extension;
    430 }
    431 
    432 namespace {
    433 const char* kGalleryUpdateHttpUrl =
    434     "http://clients2.google.com/service/update2/crx";
    435 const char* kGalleryUpdateHttpsUrl =
    436     "https://clients2.google.com/service/update2/crx";
    437 }  // namespace
    438 
    439 // static
    440 GURL Extension::GalleryUpdateUrl(bool secure) {
    441   CommandLine* cmdline = CommandLine::ForCurrentProcess();
    442   if (cmdline->HasSwitch(switches::kAppsGalleryUpdateURL))
    443     return GURL(cmdline->GetSwitchValueASCII(switches::kAppsGalleryUpdateURL));
    444   else
    445     return GURL(secure ? kGalleryUpdateHttpsUrl : kGalleryUpdateHttpUrl);
    446 }
    447 
    448 // static
    449 Extension::Location Extension::GetHigherPriorityLocation(
    450     Extension::Location loc1, Extension::Location loc2) {
    451   if (loc1 == loc2)
    452     return loc1;
    453 
    454   int loc1_rank = GetLocationRank(loc1);
    455   int loc2_rank = GetLocationRank(loc2);
    456 
    457   // If two different locations have the same rank, then we can not
    458   // deterministicly choose a location.
    459   CHECK(loc1_rank != loc2_rank);
    460 
    461   // Lowest rank has highest priority.
    462   return (loc1_rank > loc2_rank ? loc1 : loc2 );
    463 }
    464 
    465 // static
    466 Extension::PermissionMessage::MessageId Extension::GetPermissionMessageId(
    467     const std::string& permission) {
    468   return ExtensionConfig::GetInstance()->GetPermissionMessageId(permission);
    469 }
    470 
    471 Extension::PermissionMessages Extension::GetPermissionMessages() const {
    472   PermissionMessages messages;
    473   if (!plugins().empty()) {
    474     messages.push_back(PermissionMessage::CreateFromMessageId(
    475         PermissionMessage::ID_FULL_ACCESS));
    476     return messages;
    477   }
    478 
    479   if (HasEffectiveAccessToAllHosts()) {
    480     messages.push_back(PermissionMessage::CreateFromMessageId(
    481         PermissionMessage::ID_HOSTS_ALL));
    482   } else {
    483     std::vector<std::string> hosts = GetDistinctHostsForDisplay(
    484         GetEffectiveHostPermissions().patterns());
    485     if (!hosts.empty())
    486       messages.push_back(PermissionMessage::CreateFromHostList(hosts));
    487   }
    488 
    489   std::set<PermissionMessage> simple_msgs = GetSimplePermissionMessages();
    490   messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end());
    491 
    492   return messages;
    493 }
    494 
    495 std::vector<string16> Extension::GetPermissionMessageStrings() const {
    496   std::vector<string16> messages;
    497   PermissionMessages permissions = GetPermissionMessages();
    498   for (PermissionMessages::const_iterator i = permissions.begin();
    499        i != permissions.end(); ++i)
    500     messages.push_back(i->message());
    501   return messages;
    502 }
    503 
    504 std::set<Extension::PermissionMessage>
    505     Extension::GetSimplePermissionMessages() const {
    506   std::set<PermissionMessage> messages;
    507   std::set<std::string>::const_iterator i;
    508   for (i = api_permissions().begin(); i != api_permissions().end(); ++i) {
    509     PermissionMessage::MessageId message_id = GetPermissionMessageId(*i);
    510     DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
    511     if (message_id > PermissionMessage::ID_NONE)
    512       messages.insert(PermissionMessage::CreateFromMessageId(message_id));
    513   }
    514   return messages;
    515 }
    516 
    517 // static
    518 std::vector<std::string> Extension::GetDistinctHostsForDisplay(
    519     const URLPatternList& list) {
    520   return GetDistinctHosts(list, true);
    521 }
    522 
    523 // static
    524 bool Extension::IsElevatedHostList(
    525     const URLPatternList& old_list, const URLPatternList& new_list) {
    526   // TODO(jstritar): This is overly conservative with respect to subdomains.
    527   // For example, going from *.google.com to www.google.com will be
    528   // considered an elevation, even though it is not (http://crbug.com/65337).
    529 
    530   std::vector<std::string> new_hosts = GetDistinctHosts(new_list, false);
    531   std::vector<std::string> old_hosts = GetDistinctHosts(old_list, false);
    532 
    533   std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end());
    534   std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end());
    535   std::set<std::string> new_hosts_only;
    536 
    537   std::set_difference(new_hosts_set.begin(), new_hosts_set.end(),
    538                       old_hosts_set.begin(), old_hosts_set.end(),
    539                       std::inserter(new_hosts_only, new_hosts_only.begin()));
    540 
    541   return !new_hosts_only.empty();
    542 }
    543 
    544 // Helper for GetDistinctHosts(): com > net > org > everything else.
    545 static bool RcdBetterThan(const std::string& a, const std::string& b) {
    546   if (a == b)
    547     return false;
    548   if (a == "com")
    549     return true;
    550   if (a == "net")
    551     return b != "com";
    552   if (a == "org")
    553     return b != "com" && b != "net";
    554   return false;
    555 }
    556 
    557 // static
    558 std::vector<std::string> Extension::GetDistinctHosts(
    559     const URLPatternList& host_patterns, bool include_rcd) {
    560   // Use a vector to preserve order (also faster than a map on small sets).
    561   // Each item is a host split into two parts: host without RCDs and
    562   // current best RCD.
    563   typedef std::vector<std::pair<std::string, std::string> > HostVector;
    564   HostVector hosts_best_rcd;
    565   for (size_t i = 0; i < host_patterns.size(); ++i) {
    566     std::string host = host_patterns[i].host();
    567 
    568     // Add the subdomain wildcard back to the host, if necessary.
    569     if (host_patterns[i].match_subdomains())
    570       host = "*." + host;
    571 
    572     // If the host has an RCD, split it off so we can detect duplicates.
    573     std::string rcd;
    574     size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength(
    575         host, false);
    576     if (reg_len && reg_len != std::string::npos) {
    577       if (include_rcd)  // else leave rcd empty
    578         rcd = host.substr(host.size() - reg_len);
    579       host = host.substr(0, host.size() - reg_len);
    580     }
    581 
    582     // Check if we've already seen this host.
    583     HostVector::iterator it = hosts_best_rcd.begin();
    584     for (; it != hosts_best_rcd.end(); ++it) {
    585       if (it->first == host)
    586         break;
    587     }
    588     // If this host was found, replace the RCD if this one is better.
    589     if (it != hosts_best_rcd.end()) {
    590       if (include_rcd && RcdBetterThan(rcd, it->second))
    591         it->second = rcd;
    592     } else {  // Previously unseen host, append it.
    593       hosts_best_rcd.push_back(std::make_pair(host, rcd));
    594     }
    595   }
    596 
    597   // Build up the final vector by concatenating hosts and RCDs.
    598   std::vector<std::string> distinct_hosts;
    599   for (HostVector::iterator it = hosts_best_rcd.begin();
    600        it != hosts_best_rcd.end(); ++it)
    601     distinct_hosts.push_back(it->first + it->second);
    602   return distinct_hosts;
    603 }
    604 
    605 FilePath Extension::MaybeNormalizePath(const FilePath& path) {
    606 #if defined(OS_WIN)
    607   // Normalize any drive letter to upper-case. We do this for consistency with
    608   // net_utils::FilePathToFileURL(), which does the same thing, to make string
    609   // comparisons simpler.
    610   std::wstring path_str = path.value();
    611   if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
    612       path_str[1] == ':')
    613     path_str[0] += ('A' - 'a');
    614 
    615   return FilePath(path_str);
    616 #else
    617   return path;
    618 #endif
    619 }
    620 
    621 // static
    622 bool Extension::IsHostedAppPermission(const std::string& str) {
    623   for (size_t i = 0; i < Extension::kNumHostedAppPermissions; ++i) {
    624     if (str == Extension::kHostedAppPermissionNames[i]) {
    625       return true;
    626     }
    627   }
    628   return false;
    629 }
    630 
    631 const std::string Extension::VersionString() const {
    632   return version()->GetString();
    633 }
    634 
    635 // static
    636 bool Extension::IsExtension(const FilePath& file_name) {
    637   return file_name.MatchesExtension(chrome::kExtensionFileExtension);
    638 }
    639 
    640 // static
    641 bool Extension::IdIsValid(const std::string& id) {
    642   // Verify that the id is legal.
    643   if (id.size() != (kIdSize * 2))
    644     return false;
    645 
    646   // We only support lowercase IDs, because IDs can be used as URL components
    647   // (where GURL will lowercase it).
    648   std::string temp = StringToLowerASCII(id);
    649   for (size_t i = 0; i < temp.size(); i++)
    650     if (temp[i] < 'a' || temp[i] > 'p')
    651       return false;
    652 
    653   return true;
    654 }
    655 
    656 // static
    657 std::string Extension::GenerateIdForPath(const FilePath& path) {
    658   FilePath new_path = Extension::MaybeNormalizePath(path);
    659   std::string path_bytes =
    660       std::string(reinterpret_cast<const char*>(new_path.value().data()),
    661                   new_path.value().size() * sizeof(FilePath::CharType));
    662   std::string id;
    663   if (!GenerateId(path_bytes, &id))
    664     return "";
    665   return id;
    666 }
    667 
    668 Extension::Type Extension::GetType() const {
    669   if (is_theme())
    670     return TYPE_THEME;
    671   if (converted_from_user_script())
    672     return TYPE_USER_SCRIPT;
    673   if (is_hosted_app())
    674     return TYPE_HOSTED_APP;
    675   if (is_packaged_app())
    676     return TYPE_PACKAGED_APP;
    677   return TYPE_EXTENSION;
    678 }
    679 
    680 // static
    681 GURL Extension::GetResourceURL(const GURL& extension_url,
    682                                const std::string& relative_path) {
    683   DCHECK(extension_url.SchemeIs(chrome::kExtensionScheme));
    684   DCHECK_EQ("/", extension_url.path());
    685 
    686   GURL ret_val = GURL(extension_url.spec() + relative_path);
    687   DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
    688 
    689   return ret_val;
    690 }
    691 
    692 bool Extension::GenerateId(const std::string& input, std::string* output) {
    693   CHECK(output);
    694   uint8 hash[Extension::kIdSize];
    695   crypto::SHA256HashString(input, hash, sizeof(hash));
    696   *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash)));
    697   ConvertHexadecimalToIDAlphabet(output);
    698 
    699   return true;
    700 }
    701 
    702 // Helper method that loads a UserScript object from a dictionary in the
    703 // content_script list of the manifest.
    704 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
    705                                      int definition_index,
    706                                      int flags,
    707                                      std::string* error,
    708                                      UserScript* result) {
    709   // When strict error checks are enabled, make URL pattern parsing strict.
    710   URLPattern::ParseOption parse_strictness =
    711       (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT
    712                                    : URLPattern::PARSE_LENIENT);
    713 
    714   // run_at
    715   if (content_script->HasKey(keys::kRunAt)) {
    716     std::string run_location;
    717     if (!content_script->GetString(keys::kRunAt, &run_location)) {
    718       *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidRunAt,
    719           base::IntToString(definition_index));
    720       return false;
    721     }
    722 
    723     if (run_location == values::kRunAtDocumentStart) {
    724       result->set_run_location(UserScript::DOCUMENT_START);
    725     } else if (run_location == values::kRunAtDocumentEnd) {
    726       result->set_run_location(UserScript::DOCUMENT_END);
    727     } else if (run_location == values::kRunAtDocumentIdle) {
    728       result->set_run_location(UserScript::DOCUMENT_IDLE);
    729     } else {
    730       *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidRunAt,
    731           base::IntToString(definition_index));
    732       return false;
    733     }
    734   }
    735 
    736   // all frames
    737   if (content_script->HasKey(keys::kAllFrames)) {
    738     bool all_frames = false;
    739     if (!content_script->GetBoolean(keys::kAllFrames, &all_frames)) {
    740       *error = ExtensionErrorUtils::FormatErrorMessage(
    741             errors::kInvalidAllFrames, base::IntToString(definition_index));
    742       return false;
    743     }
    744     result->set_match_all_frames(all_frames);
    745   }
    746 
    747   // matches
    748   ListValue* matches = NULL;
    749   if (!content_script->GetList(keys::kMatches, &matches)) {
    750     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidMatches,
    751         base::IntToString(definition_index));
    752     return false;
    753   }
    754 
    755   if (matches->GetSize() == 0) {
    756     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidMatchCount,
    757         base::IntToString(definition_index));
    758     return false;
    759   }
    760   for (size_t j = 0; j < matches->GetSize(); ++j) {
    761     std::string match_str;
    762     if (!matches->GetString(j, &match_str)) {
    763       *error = ExtensionErrorUtils::FormatErrorMessage(
    764           errors::kInvalidMatch,
    765           base::IntToString(definition_index),
    766           base::IntToString(j),
    767           errors::kExpectString);
    768       return false;
    769     }
    770 
    771     URLPattern pattern(UserScript::kValidUserScriptSchemes);
    772     if (CanExecuteScriptEverywhere())
    773       pattern.set_valid_schemes(URLPattern::SCHEME_ALL);
    774 
    775     URLPattern::ParseResult parse_result = pattern.Parse(match_str,
    776                                                          parse_strictness);
    777     if (parse_result != URLPattern::PARSE_SUCCESS) {
    778       *error = ExtensionErrorUtils::FormatErrorMessage(
    779           errors::kInvalidMatch,
    780           base::IntToString(definition_index),
    781           base::IntToString(j),
    782           URLPattern::GetParseResultString(parse_result));
    783       return false;
    784     }
    785 
    786     if (pattern.MatchesScheme(chrome::kFileScheme) &&
    787         !CanExecuteScriptEverywhere()) {
    788       wants_file_access_ = true;
    789       if (!(flags & ALLOW_FILE_ACCESS))
    790         pattern.set_valid_schemes(
    791             pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
    792     }
    793 
    794     result->add_url_pattern(pattern);
    795   }
    796 
    797   // include/exclude globs (mostly for Greasemonkey compatibility)
    798   if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
    799                        error, &UserScript::add_glob, result)) {
    800       return false;
    801   }
    802 
    803   if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
    804                        error, &UserScript::add_exclude_glob, result)) {
    805       return false;
    806   }
    807 
    808   // js and css keys
    809   ListValue* js = NULL;
    810   if (content_script->HasKey(keys::kJs) &&
    811       !content_script->GetList(keys::kJs, &js)) {
    812     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidJsList,
    813         base::IntToString(definition_index));
    814     return false;
    815   }
    816 
    817   ListValue* css = NULL;
    818   if (content_script->HasKey(keys::kCss) &&
    819       !content_script->GetList(keys::kCss, &css)) {
    820     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidCssList,
    821         base::IntToString(definition_index));
    822     return false;
    823   }
    824 
    825   // The manifest needs to have at least one js or css user script definition.
    826   if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
    827     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kMissingFile,
    828         base::IntToString(definition_index));
    829     return false;
    830   }
    831 
    832   if (js) {
    833     for (size_t script_index = 0; script_index < js->GetSize();
    834          ++script_index) {
    835       Value* value;
    836       std::string relative;
    837       if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
    838         *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidJs,
    839             base::IntToString(definition_index),
    840             base::IntToString(script_index));
    841         return false;
    842       }
    843       GURL url = GetResourceURL(relative);
    844       ExtensionResource resource = GetResource(relative);
    845       result->js_scripts().push_back(UserScript::File(
    846           resource.extension_root(), resource.relative_path(), url));
    847     }
    848   }
    849 
    850   if (css) {
    851     for (size_t script_index = 0; script_index < css->GetSize();
    852          ++script_index) {
    853       Value* value;
    854       std::string relative;
    855       if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
    856         *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidCss,
    857             base::IntToString(definition_index),
    858             base::IntToString(script_index));
    859         return false;
    860       }
    861       GURL url = GetResourceURL(relative);
    862       ExtensionResource resource = GetResource(relative);
    863       result->css_scripts().push_back(UserScript::File(
    864           resource.extension_root(), resource.relative_path(), url));
    865     }
    866   }
    867 
    868   return true;
    869 }
    870 
    871 bool Extension::LoadGlobsHelper(
    872     const DictionaryValue* content_script,
    873     int content_script_index,
    874     const char* globs_property_name,
    875     std::string* error,
    876     void(UserScript::*add_method)(const std::string& glob),
    877     UserScript *instance) {
    878   if (!content_script->HasKey(globs_property_name))
    879     return true;  // they are optional
    880 
    881   ListValue* list = NULL;
    882   if (!content_script->GetList(globs_property_name, &list)) {
    883     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidGlobList,
    884         base::IntToString(content_script_index),
    885         globs_property_name);
    886     return false;
    887   }
    888 
    889   for (size_t i = 0; i < list->GetSize(); ++i) {
    890     std::string glob;
    891     if (!list->GetString(i, &glob)) {
    892       *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidGlob,
    893           base::IntToString(content_script_index),
    894           globs_property_name,
    895           base::IntToString(i));
    896       return false;
    897     }
    898 
    899     (instance->*add_method)(glob);
    900   }
    901 
    902   return true;
    903 }
    904 
    905 ExtensionAction* Extension::LoadExtensionActionHelper(
    906     const DictionaryValue* extension_action, std::string* error) {
    907   scoped_ptr<ExtensionAction> result(new ExtensionAction());
    908   result->set_extension_id(id());
    909 
    910   // Page actions are hidden by default, and browser actions ignore
    911   // visibility.
    912   result->SetIsVisible(ExtensionAction::kDefaultTabId, false);
    913 
    914   // TODO(EXTENSIONS_DEPRECATED): icons list is obsolete.
    915   ListValue* icons = NULL;
    916   if (extension_action->HasKey(keys::kPageActionIcons) &&
    917       extension_action->GetList(keys::kPageActionIcons, &icons)) {
    918     for (ListValue::const_iterator iter = icons->begin();
    919          iter != icons->end(); ++iter) {
    920       std::string path;
    921       if (!(*iter)->GetAsString(&path) || path.empty()) {
    922         *error = errors::kInvalidPageActionIconPath;
    923         return NULL;
    924       }
    925 
    926       result->icon_paths()->push_back(path);
    927     }
    928   }
    929 
    930   // TODO(EXTENSIONS_DEPRECATED): Read the page action |id| (optional).
    931   std::string id;
    932   if (extension_action->HasKey(keys::kPageActionId)) {
    933     if (!extension_action->GetString(keys::kPageActionId, &id)) {
    934       *error = errors::kInvalidPageActionId;
    935       return NULL;
    936     }
    937     result->set_id(id);
    938   }
    939 
    940   std::string default_icon;
    941   // Read the page action |default_icon| (optional).
    942   if (extension_action->HasKey(keys::kPageActionDefaultIcon)) {
    943     if (!extension_action->GetString(keys::kPageActionDefaultIcon,
    944                                      &default_icon) ||
    945         default_icon.empty()) {
    946       *error = errors::kInvalidPageActionIconPath;
    947       return NULL;
    948     }
    949     result->set_default_icon_path(default_icon);
    950   }
    951 
    952   // Read the page action title from |default_title| if present, |name| if not
    953   // (both optional).
    954   std::string title;
    955   if (extension_action->HasKey(keys::kPageActionDefaultTitle)) {
    956     if (!extension_action->GetString(keys::kPageActionDefaultTitle, &title)) {
    957       *error = errors::kInvalidPageActionDefaultTitle;
    958       return NULL;
    959     }
    960   } else if (extension_action->HasKey(keys::kName)) {
    961     if (!extension_action->GetString(keys::kName, &title)) {
    962       *error = errors::kInvalidPageActionName;
    963       return NULL;
    964     }
    965   }
    966   result->SetTitle(ExtensionAction::kDefaultTabId, title);
    967 
    968   // Read the action's |popup| (optional).
    969   const char* popup_key = NULL;
    970   if (extension_action->HasKey(keys::kPageActionDefaultPopup))
    971     popup_key = keys::kPageActionDefaultPopup;
    972 
    973   // For backward compatibility, alias old key "popup" to new
    974   // key "default_popup".
    975   if (extension_action->HasKey(keys::kPageActionPopup)) {
    976     if (popup_key) {
    977       *error = ExtensionErrorUtils::FormatErrorMessage(
    978           errors::kInvalidPageActionOldAndNewKeys,
    979           keys::kPageActionDefaultPopup,
    980           keys::kPageActionPopup);
    981       return NULL;
    982     }
    983     popup_key = keys::kPageActionPopup;
    984   }
    985 
    986   if (popup_key) {
    987     DictionaryValue* popup = NULL;
    988     std::string url_str;
    989 
    990     if (extension_action->GetString(popup_key, &url_str)) {
    991       // On success, |url_str| is set.  Nothing else to do.
    992     } else if (extension_action->GetDictionary(popup_key, &popup)) {
    993       // TODO(EXTENSIONS_DEPRECATED): popup is now a string only.
    994       // Support the old dictionary format for backward compatibility.
    995       if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
    996         *error = ExtensionErrorUtils::FormatErrorMessage(
    997             errors::kInvalidPageActionPopupPath, "<missing>");
    998         return NULL;
    999       }
   1000     } else {
   1001       *error = errors::kInvalidPageActionPopup;
   1002       return NULL;
   1003     }
   1004 
   1005     if (!url_str.empty()) {
   1006       // An empty string is treated as having no popup.
   1007       GURL url = GetResourceURL(url_str);
   1008       if (!url.is_valid()) {
   1009         *error = ExtensionErrorUtils::FormatErrorMessage(
   1010             errors::kInvalidPageActionPopupPath, url_str);
   1011         return NULL;
   1012       }
   1013       result->SetPopupUrl(ExtensionAction::kDefaultTabId, url);
   1014     } else {
   1015       DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId))
   1016           << "Shouldn't be posible for the popup to be set.";
   1017     }
   1018   }
   1019 
   1020   return result.release();
   1021 }
   1022 
   1023 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlers(
   1024     const ListValue* extension_actions, std::string* error) {
   1025   scoped_ptr<FileBrowserHandlerList> result(
   1026       new FileBrowserHandlerList());
   1027   for (ListValue::const_iterator iter = extension_actions->begin();
   1028        iter != extension_actions->end();
   1029        ++iter) {
   1030     if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
   1031       *error = errors::kInvalidFileBrowserHandler;
   1032       return NULL;
   1033     }
   1034     scoped_ptr<FileBrowserHandler> action(
   1035         LoadFileBrowserHandler(
   1036             reinterpret_cast<DictionaryValue*>(*iter), error));
   1037     if (!action.get())
   1038       return NULL;  // Failed to parse file browser action definition.
   1039     result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
   1040   }
   1041   return result.release();
   1042 }
   1043 
   1044 FileBrowserHandler* Extension::LoadFileBrowserHandler(
   1045     const DictionaryValue* file_browser_handler, std::string* error) {
   1046   scoped_ptr<FileBrowserHandler> result(
   1047       new FileBrowserHandler());
   1048   result->set_extension_id(id());
   1049 
   1050   std::string id;
   1051   // Read the file action |id| (mandatory).
   1052   if (!file_browser_handler->HasKey(keys::kPageActionId) ||
   1053       !file_browser_handler->GetString(keys::kPageActionId, &id)) {
   1054     *error = errors::kInvalidPageActionId;
   1055     return NULL;
   1056   }
   1057   result->set_id(id);
   1058 
   1059   // Read the page action title from |default_title| (mandatory).
   1060   std::string title;
   1061   if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) ||
   1062       !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) {
   1063     *error = errors::kInvalidPageActionDefaultTitle;
   1064     return NULL;
   1065   }
   1066   result->set_title(title);
   1067 
   1068   // Initialize file filters (mandatory).
   1069   ListValue* list_value = NULL;
   1070   if (!file_browser_handler->HasKey(keys::kFileFilters) ||
   1071       !file_browser_handler->GetList(keys::kFileFilters, &list_value) ||
   1072       list_value->empty()) {
   1073     *error = errors::kInvalidFileFiltersList;
   1074     return NULL;
   1075   }
   1076   for (size_t i = 0; i < list_value->GetSize(); ++i) {
   1077     std::string filter;
   1078     if (!list_value->GetString(i, &filter)) {
   1079       *error = ExtensionErrorUtils::FormatErrorMessage(
   1080           errors::kInvalidFileFilterValue, base::IntToString(i));
   1081       return NULL;
   1082     }
   1083     URLPattern pattern(URLPattern::SCHEME_FILESYSTEM);
   1084     if (URLPattern::PARSE_SUCCESS != pattern.Parse(filter,
   1085                                                    URLPattern::PARSE_STRICT)) {
   1086       *error = ExtensionErrorUtils::FormatErrorMessage(
   1087           errors::kInvalidURLPatternError, filter);
   1088       return NULL;
   1089     }
   1090     result->AddPattern(pattern);
   1091   }
   1092 
   1093   std::string default_icon;
   1094   // Read the file browser action |default_icon| (optional).
   1095   if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
   1096     if (!file_browser_handler->GetString(
   1097             keys::kPageActionDefaultIcon,&default_icon) ||
   1098         default_icon.empty()) {
   1099       *error = errors::kInvalidPageActionIconPath;
   1100       return NULL;
   1101     }
   1102     result->set_icon_path(default_icon);
   1103   }
   1104 
   1105   return result.release();
   1106 }
   1107 
   1108 ExtensionSidebarDefaults* Extension::LoadExtensionSidebarDefaults(
   1109     const DictionaryValue* extension_sidebar, std::string* error) {
   1110   scoped_ptr<ExtensionSidebarDefaults> result(new ExtensionSidebarDefaults());
   1111 
   1112   std::string default_icon;
   1113   // Read sidebar's |default_icon| (optional).
   1114   if (extension_sidebar->HasKey(keys::kSidebarDefaultIcon)) {
   1115     if (!extension_sidebar->GetString(keys::kSidebarDefaultIcon,
   1116                                       &default_icon) ||
   1117         default_icon.empty()) {
   1118       *error = errors::kInvalidSidebarDefaultIconPath;
   1119       return NULL;
   1120     }
   1121     result->set_default_icon_path(default_icon);
   1122   }
   1123 
   1124   // Read sidebar's |default_title| (optional).
   1125   string16 default_title;
   1126   if (extension_sidebar->HasKey(keys::kSidebarDefaultTitle)) {
   1127     if (!extension_sidebar->GetString(keys::kSidebarDefaultTitle,
   1128                                       &default_title)) {
   1129       *error = errors::kInvalidSidebarDefaultTitle;
   1130       return NULL;
   1131     }
   1132   }
   1133   result->set_default_title(default_title);
   1134 
   1135   // Read sidebar's |default_page| (optional).
   1136   std::string default_page;
   1137   if (extension_sidebar->HasKey(keys::kSidebarDefaultPage)) {
   1138     if (!extension_sidebar->GetString(keys::kSidebarDefaultPage,
   1139                                       &default_page) ||
   1140         default_page.empty()) {
   1141       *error = errors::kInvalidSidebarDefaultPage;
   1142       return NULL;
   1143     }
   1144     GURL url = extension_sidebar_utils::ResolveRelativePath(
   1145         default_page, this, error);
   1146     if (!url.is_valid())
   1147       return NULL;
   1148     result->set_default_page(url);
   1149   }
   1150 
   1151   return result.release();
   1152 }
   1153 
   1154 bool Extension::ContainsNonThemeKeys(const DictionaryValue& source) const {
   1155   for (DictionaryValue::key_iterator key = source.begin_keys();
   1156        key != source.end_keys(); ++key) {
   1157     if (!IsBaseCrxKey(*key) && *key != keys::kTheme)
   1158       return true;
   1159   }
   1160   return false;
   1161 }
   1162 
   1163 bool Extension::LoadIsApp(const DictionaryValue* manifest,
   1164                           std::string* error) {
   1165   if (manifest->HasKey(keys::kApp))
   1166     is_app_ = true;
   1167 
   1168   return true;
   1169 }
   1170 
   1171 bool Extension::LoadExtent(const DictionaryValue* manifest,
   1172                            const char* key,
   1173                            ExtensionExtent* extent,
   1174                            const char* list_error,
   1175                            const char* value_error,
   1176                            URLPattern::ParseOption parse_strictness,
   1177                            std::string* error) {
   1178   Value* temp = NULL;
   1179   if (!manifest->Get(key, &temp))
   1180     return true;
   1181 
   1182   if (temp->GetType() != Value::TYPE_LIST) {
   1183     *error = list_error;
   1184     return false;
   1185   }
   1186 
   1187   ListValue* pattern_list = static_cast<ListValue*>(temp);
   1188   for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
   1189     std::string pattern_string;
   1190     if (!pattern_list->GetString(i, &pattern_string)) {
   1191       *error = ExtensionErrorUtils::FormatErrorMessage(value_error,
   1192                                                        base::UintToString(i),
   1193                                                        errors::kExpectString);
   1194       return false;
   1195     }
   1196 
   1197     URLPattern pattern(kValidWebExtentSchemes);
   1198     URLPattern::ParseResult parse_result = pattern.Parse(pattern_string,
   1199                                                          parse_strictness);
   1200     if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
   1201       pattern_string += "/";
   1202       parse_result = pattern.Parse(pattern_string, parse_strictness);
   1203     }
   1204 
   1205     if (parse_result != URLPattern::PARSE_SUCCESS) {
   1206       *error = ExtensionErrorUtils::FormatErrorMessage(
   1207           value_error,
   1208           base::UintToString(i),
   1209           URLPattern::GetParseResultString(parse_result));
   1210       return false;
   1211     }
   1212 
   1213     // Do not allow authors to claim "<all_urls>".
   1214     if (pattern.match_all_urls()) {
   1215       *error = ExtensionErrorUtils::FormatErrorMessage(
   1216           value_error,
   1217           base::UintToString(i),
   1218           errors::kCannotClaimAllURLsInExtent);
   1219       return false;
   1220     }
   1221 
   1222     // Do not allow authors to claim "*" for host.
   1223     if (pattern.host().empty()) {
   1224       *error = ExtensionErrorUtils::FormatErrorMessage(
   1225           value_error,
   1226           base::UintToString(i),
   1227           errors::kCannotClaimAllHostsInExtent);
   1228       return false;
   1229     }
   1230 
   1231     // We do not allow authors to put wildcards in their paths. Instead, we
   1232     // imply one at the end.
   1233     if (pattern.path().find('*') != std::string::npos) {
   1234       *error = ExtensionErrorUtils::FormatErrorMessage(
   1235           value_error,
   1236           base::UintToString(i),
   1237           errors::kNoWildCardsInPaths);
   1238       return false;
   1239     }
   1240     pattern.SetPath(pattern.path() + '*');
   1241 
   1242     extent->AddPattern(pattern);
   1243   }
   1244 
   1245   return true;
   1246 }
   1247 
   1248 bool Extension::LoadLaunchURL(const DictionaryValue* manifest,
   1249                               std::string* error) {
   1250   Value* temp = NULL;
   1251 
   1252   // launch URL can be either local (to chrome-extension:// root) or an absolute
   1253   // web URL.
   1254   if (manifest->Get(keys::kLaunchLocalPath, &temp)) {
   1255     if (manifest->Get(keys::kLaunchWebURL, NULL)) {
   1256       *error = errors::kLaunchPathAndURLAreExclusive;
   1257       return false;
   1258     }
   1259 
   1260     std::string launch_path;
   1261     if (!temp->GetAsString(&launch_path)) {
   1262       *error = errors::kInvalidLaunchLocalPath;
   1263       return false;
   1264     }
   1265 
   1266     // Ensure the launch path is a valid relative URL.
   1267     GURL resolved = url().Resolve(launch_path);
   1268     if (!resolved.is_valid() || resolved.GetOrigin() != url()) {
   1269       *error = errors::kInvalidLaunchLocalPath;
   1270       return false;
   1271     }
   1272 
   1273     launch_local_path_ = launch_path;
   1274   } else if (manifest->Get(keys::kLaunchWebURL, &temp)) {
   1275     std::string launch_url;
   1276     if (!temp->GetAsString(&launch_url)) {
   1277       *error = errors::kInvalidLaunchWebURL;
   1278       return false;
   1279     }
   1280 
   1281     // Ensure the launch URL is a valid absolute URL and web extent scheme.
   1282     GURL url(launch_url);
   1283     URLPattern pattern(kValidWebExtentSchemes);
   1284     if (!url.is_valid() || !pattern.SetScheme(url.scheme())) {
   1285       *error = errors::kInvalidLaunchWebURL;
   1286       return false;
   1287     }
   1288 
   1289     launch_web_url_ = launch_url;
   1290   } else if (is_app()) {
   1291     *error = errors::kLaunchURLRequired;
   1292     return false;
   1293   }
   1294 
   1295   // If there is no extent, we default the extent based on the launch URL.
   1296   if (web_extent().is_empty() && !launch_web_url().empty()) {
   1297     GURL launch_url(launch_web_url());
   1298     URLPattern pattern(kValidWebExtentSchemes);
   1299     if (!pattern.SetScheme("*")) {
   1300       *error = errors::kInvalidLaunchWebURL;
   1301       return false;
   1302     }
   1303     pattern.set_host(launch_url.host());
   1304     pattern.SetPath("/*");
   1305     extent_.AddPattern(pattern);
   1306   }
   1307 
   1308   // In order for the --apps-gallery-url switch to work with the gallery
   1309   // process isolation, we must insert any provided value into the component
   1310   // app's launch url and web extent.
   1311   if (id() == extension_misc::kWebStoreAppId) {
   1312     std::string gallery_url_str = CommandLine::ForCurrentProcess()->
   1313         GetSwitchValueASCII(switches::kAppsGalleryURL);
   1314 
   1315     // Empty string means option was not used.
   1316     if (!gallery_url_str.empty()) {
   1317       GURL gallery_url(gallery_url_str);
   1318       if (!gallery_url.is_valid()) {
   1319         LOG(WARNING) << "Invalid url given in switch "
   1320                      << switches::kAppsGalleryURL;
   1321       } else {
   1322         if (gallery_url.has_port()) {
   1323           LOG(WARNING) << "URLs passed to switch " << switches::kAppsGalleryURL
   1324                        << " should not contain a port.  Removing it.";
   1325 
   1326           GURL::Replacements remove_port;
   1327           remove_port.ClearPort();
   1328           gallery_url = gallery_url.ReplaceComponents(remove_port);
   1329         }
   1330 
   1331         launch_web_url_ = gallery_url.spec();
   1332 
   1333         URLPattern pattern(kValidWebExtentSchemes);
   1334         pattern.Parse(gallery_url.spec(), URLPattern::PARSE_STRICT);
   1335         pattern.SetPath(pattern.path() + '*');
   1336         extent_.AddPattern(pattern);
   1337       }
   1338     }
   1339   }
   1340 
   1341   return true;
   1342 }
   1343 
   1344 bool Extension::LoadLaunchContainer(const DictionaryValue* manifest,
   1345                                     std::string* error) {
   1346   Value* temp = NULL;
   1347   if (!manifest->Get(keys::kLaunchContainer, &temp))
   1348     return true;
   1349 
   1350   std::string launch_container_string;
   1351   if (!temp->GetAsString(&launch_container_string)) {
   1352     *error = errors::kInvalidLaunchContainer;
   1353     return false;
   1354   }
   1355 
   1356   if (launch_container_string == values::kLaunchContainerPanel) {
   1357     launch_container_ = extension_misc::LAUNCH_PANEL;
   1358   } else if (launch_container_string == values::kLaunchContainerTab) {
   1359     launch_container_ = extension_misc::LAUNCH_TAB;
   1360   } else {
   1361     *error = errors::kInvalidLaunchContainer;
   1362     return false;
   1363   }
   1364 
   1365   // Validate the container width if present.
   1366   if (manifest->Get(keys::kLaunchWidth, &temp)) {
   1367     if (launch_container() != extension_misc::LAUNCH_PANEL &&
   1368         launch_container() != extension_misc::LAUNCH_WINDOW) {
   1369       *error = errors::kInvalidLaunchWidthContainer;
   1370       return false;
   1371     }
   1372     if (!temp->GetAsInteger(&launch_width_) ||
   1373         launch_width_ < 0) {
   1374       launch_width_ = 0;
   1375       *error = errors::kInvalidLaunchWidth;
   1376       return false;
   1377     }
   1378   }
   1379 
   1380   // Validate container height if present.
   1381   if (manifest->Get(keys::kLaunchHeight, &temp)) {
   1382     if (launch_container() != extension_misc::LAUNCH_PANEL &&
   1383         launch_container() != extension_misc::LAUNCH_WINDOW) {
   1384       *error = errors::kInvalidLaunchHeightContainer;
   1385       return false;
   1386     }
   1387     if (!temp->GetAsInteger(&launch_height_) || launch_height_ < 0) {
   1388       launch_height_ = 0;
   1389       *error = errors::kInvalidLaunchHeight;
   1390       return false;
   1391     }
   1392   }
   1393 
   1394   return true;
   1395 }
   1396 
   1397 bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
   1398                                  std::string* error) {
   1399   // Only parse app isolation features if this switch is present.
   1400   if (!CommandLine::ForCurrentProcess()->HasSwitch(
   1401           switches::kEnableExperimentalAppManifests))
   1402     return true;
   1403 
   1404   Value* temp = NULL;
   1405   if (!manifest->Get(keys::kIsolation, &temp))
   1406     return true;
   1407 
   1408   if (temp->GetType() != Value::TYPE_LIST) {
   1409     *error = errors::kInvalidIsolation;
   1410     return false;
   1411   }
   1412 
   1413   ListValue* isolation_list = static_cast<ListValue*>(temp);
   1414   for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
   1415     std::string isolation_string;
   1416     if (!isolation_list->GetString(i, &isolation_string)) {
   1417       *error = ExtensionErrorUtils::FormatErrorMessage(
   1418           errors::kInvalidIsolationValue,
   1419           base::UintToString(i));
   1420       return false;
   1421     }
   1422 
   1423     // Check for isolated storage.
   1424     if (isolation_string == values::kIsolatedStorage) {
   1425       is_storage_isolated_ = true;
   1426     } else {
   1427       LOG(WARNING) << "Did not recognize isolation type: "
   1428                    << isolation_string;
   1429     }
   1430   }
   1431   return true;
   1432 }
   1433 
   1434 bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
   1435                                    std::string* error) {
   1436   if (web_extent().is_empty())
   1437     return true;
   1438 
   1439   for (DictionaryValue::key_iterator key = manifest->begin_keys();
   1440        key != manifest->end_keys(); ++key) {
   1441     if (!IsBaseCrxKey(*key) &&
   1442         *key != keys::kApp &&
   1443         *key != keys::kPermissions &&
   1444         *key != keys::kOptionsPage &&
   1445         *key != keys::kBackground) {
   1446       *error = ExtensionErrorUtils::FormatErrorMessage(
   1447           errors::kHostedAppsCannotIncludeExtensionFeatures, *key);
   1448       return false;
   1449     }
   1450   }
   1451 
   1452   return true;
   1453 }
   1454 
   1455 Extension::Extension(const FilePath& path, Location location)
   1456     : incognito_split_mode_(false),
   1457       location_(location),
   1458       converted_from_user_script_(false),
   1459       is_theme_(false),
   1460       is_app_(false),
   1461       is_storage_isolated_(false),
   1462       launch_container_(extension_misc::LAUNCH_TAB),
   1463       launch_width_(0),
   1464       launch_height_(0),
   1465       wants_file_access_(false) {
   1466   DCHECK(path.empty() || path.IsAbsolute());
   1467   path_ = MaybeNormalizePath(path);
   1468 }
   1469 
   1470 Extension::~Extension() {
   1471 }
   1472 
   1473 ExtensionResource Extension::GetResource(
   1474     const std::string& relative_path) const {
   1475 #if defined(OS_POSIX)
   1476   FilePath relative_file_path(relative_path);
   1477 #elif defined(OS_WIN)
   1478   FilePath relative_file_path(UTF8ToWide(relative_path));
   1479 #endif
   1480   return ExtensionResource(id(), path(), relative_file_path);
   1481 }
   1482 
   1483 ExtensionResource Extension::GetResource(
   1484     const FilePath& relative_file_path) const {
   1485   return ExtensionResource(id(), path(), relative_file_path);
   1486 }
   1487 
   1488 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
   1489 // util class in base:
   1490 // http://code.google.com/p/chromium/issues/detail?id=13572
   1491 bool Extension::ParsePEMKeyBytes(const std::string& input,
   1492                                  std::string* output) {
   1493   DCHECK(output);
   1494   if (!output)
   1495     return false;
   1496   if (input.length() == 0)
   1497     return false;
   1498 
   1499   std::string working = input;
   1500   if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
   1501     working = CollapseWhitespaceASCII(working, true);
   1502     size_t header_pos = working.find(kKeyInfoEndMarker,
   1503       sizeof(kKeyBeginHeaderMarker) - 1);
   1504     if (header_pos == std::string::npos)
   1505       return false;
   1506     size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
   1507     size_t end_pos = working.rfind(kKeyBeginFooterMarker);
   1508     if (end_pos == std::string::npos)
   1509       return false;
   1510     if (start_pos >= end_pos)
   1511       return false;
   1512 
   1513     working = working.substr(start_pos, end_pos - start_pos);
   1514     if (working.length() == 0)
   1515       return false;
   1516   }
   1517 
   1518   return base::Base64Decode(working, output);
   1519 }
   1520 
   1521 bool Extension::ProducePEM(const std::string& input, std::string* output) {
   1522   CHECK(output);
   1523   if (input.length() == 0)
   1524     return false;
   1525 
   1526   return base::Base64Encode(input, output);
   1527 }
   1528 
   1529 bool Extension::FormatPEMForFileOutput(const std::string& input,
   1530                                        std::string* output,
   1531                                        bool is_public) {
   1532   CHECK(output);
   1533   if (input.length() == 0)
   1534     return false;
   1535   *output = "";
   1536   output->append(kKeyBeginHeaderMarker);
   1537   output->append(" ");
   1538   output->append(is_public ? kPublic : kPrivate);
   1539   output->append(" ");
   1540   output->append(kKeyInfoEndMarker);
   1541   output->append("\n");
   1542   for (size_t i = 0; i < input.length(); ) {
   1543     int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
   1544     output->append(input.substr(i, slice));
   1545     output->append("\n");
   1546     i += slice;
   1547   }
   1548   output->append(kKeyBeginFooterMarker);
   1549   output->append(" ");
   1550   output->append(is_public ? kPublic : kPrivate);
   1551   output->append(" ");
   1552   output->append(kKeyInfoEndMarker);
   1553   output->append("\n");
   1554 
   1555   return true;
   1556 }
   1557 
   1558 // static
   1559 bool Extension::IsPrivilegeIncrease(const bool granted_full_access,
   1560                                     const std::set<std::string>& granted_apis,
   1561                                     const ExtensionExtent& granted_extent,
   1562                                     const Extension* new_extension) {
   1563   // If the extension had native code access, we don't need to go any further.
   1564   // Things can't get any worse.
   1565   if (granted_full_access)
   1566     return false;
   1567 
   1568   // Otherwise, if the new extension has a plugin, it's a privilege increase.
   1569   if (new_extension->HasFullPermissions())
   1570     return true;
   1571 
   1572   // If the extension hadn't been granted access to all hosts in the past, then
   1573   // see if the extension requires more host permissions.
   1574   if (!HasEffectiveAccessToAllHosts(granted_extent, granted_apis)) {
   1575     if (new_extension->HasEffectiveAccessToAllHosts())
   1576       return true;
   1577 
   1578     const ExtensionExtent new_extent =
   1579         new_extension->GetEffectiveHostPermissions();
   1580 
   1581     if (IsElevatedHostList(granted_extent.patterns(), new_extent.patterns()))
   1582       return true;
   1583   }
   1584 
   1585   std::set<std::string> new_apis = new_extension->api_permissions();
   1586   std::set<std::string> new_apis_only;
   1587   std::set_difference(new_apis.begin(), new_apis.end(),
   1588                       granted_apis.begin(), granted_apis.end(),
   1589                       std::inserter(new_apis_only, new_apis_only.begin()));
   1590 
   1591   // Ignore API permissions that don't require user approval when deciding if
   1592   // an extension has increased its privileges.
   1593   size_t new_api_count = 0;
   1594   for (std::set<std::string>::iterator i = new_apis_only.begin();
   1595        i != new_apis_only.end(); ++i) {
   1596     DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
   1597     if (GetPermissionMessageId(*i) > PermissionMessage::ID_NONE)
   1598       new_api_count++;
   1599   }
   1600 
   1601   if (new_api_count)
   1602     return true;
   1603 
   1604   return false;
   1605 }
   1606 
   1607 // static
   1608 void Extension::DecodeIcon(const Extension* extension,
   1609                            Icons icon_size,
   1610                            scoped_ptr<SkBitmap>* result) {
   1611   FilePath icon_path = extension->GetIconResource(
   1612       icon_size, ExtensionIconSet::MATCH_EXACTLY).GetFilePath();
   1613   DecodeIconFromPath(icon_path, icon_size, result);
   1614 }
   1615 
   1616 // static
   1617 void Extension::DecodeIconFromPath(const FilePath& icon_path,
   1618                                    Icons icon_size,
   1619                                    scoped_ptr<SkBitmap>* result) {
   1620   if (icon_path.empty())
   1621     return;
   1622 
   1623   std::string file_contents;
   1624   if (!file_util::ReadFileToString(icon_path, &file_contents)) {
   1625     LOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
   1626     return;
   1627   }
   1628 
   1629   // Decode the image using WebKit's image decoder.
   1630   const unsigned char* data =
   1631     reinterpret_cast<const unsigned char*>(file_contents.data());
   1632   webkit_glue::ImageDecoder decoder;
   1633   scoped_ptr<SkBitmap> decoded(new SkBitmap());
   1634   *decoded = decoder.Decode(data, file_contents.length());
   1635   if (decoded->empty()) {
   1636     LOG(ERROR) << "Could not decode icon file: "
   1637                << icon_path.LossyDisplayName();
   1638     return;
   1639   }
   1640 
   1641   if (decoded->width() != icon_size || decoded->height() != icon_size) {
   1642     LOG(ERROR) << "Icon file has unexpected size: "
   1643                << base::IntToString(decoded->width()) << "x"
   1644                << base::IntToString(decoded->height());
   1645     return;
   1646   }
   1647 
   1648   result->swap(decoded);
   1649 }
   1650 
   1651 // static
   1652 const SkBitmap& Extension::GetDefaultIcon(bool is_app) {
   1653   if (is_app) {
   1654     return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
   1655         IDR_APP_DEFAULT_ICON);
   1656   } else {
   1657     return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
   1658         IDR_EXTENSION_DEFAULT_ICON);
   1659   }
   1660 }
   1661 
   1662 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
   1663   return GURL(std::string(chrome::kExtensionScheme) +
   1664               chrome::kStandardSchemeSeparator + extension_id + "/");
   1665 }
   1666 
   1667 bool Extension::InitFromValue(const DictionaryValue& source, int flags,
   1668                               std::string* error) {
   1669   // When strict error checks are enabled, make URL pattern parsing strict.
   1670   URLPattern::ParseOption parse_strictness =
   1671       (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT
   1672                                    : URLPattern::PARSE_LENIENT);
   1673 
   1674   if (source.HasKey(keys::kPublicKey)) {
   1675     std::string public_key_bytes;
   1676     if (!source.GetString(keys::kPublicKey,
   1677                           &public_key_) ||
   1678         !ParsePEMKeyBytes(public_key_,
   1679                           &public_key_bytes) ||
   1680         !GenerateId(public_key_bytes, &id_)) {
   1681       *error = errors::kInvalidKey;
   1682       return false;
   1683     }
   1684   } else if (flags & REQUIRE_KEY) {
   1685     *error = errors::kInvalidKey;
   1686     return false;
   1687   } else {
   1688     // If there is a path, we generate the ID from it. This is useful for
   1689     // development mode, because it keeps the ID stable across restarts and
   1690     // reloading the extension.
   1691     id_ = Extension::GenerateIdForPath(path());
   1692     if (id_.empty()) {
   1693       NOTREACHED() << "Could not create ID from path.";
   1694       return false;
   1695     }
   1696   }
   1697 
   1698   // Make a copy of the manifest so we can store it in prefs.
   1699   manifest_value_.reset(source.DeepCopy());
   1700 
   1701   // Initialize the URL.
   1702   extension_url_ = Extension::GetBaseURLFromExtensionId(id());
   1703 
   1704   // Initialize version.
   1705   std::string version_str;
   1706   if (!source.GetString(keys::kVersion, &version_str)) {
   1707     *error = errors::kInvalidVersion;
   1708     return false;
   1709   }
   1710   version_.reset(Version::GetVersionFromString(version_str));
   1711   if (!version_.get() ||
   1712       version_->components().size() > 4) {
   1713     *error = errors::kInvalidVersion;
   1714     return false;
   1715   }
   1716 
   1717   // Initialize name.
   1718   string16 localized_name;
   1719   if (!source.GetString(keys::kName, &localized_name)) {
   1720     *error = errors::kInvalidName;
   1721     return false;
   1722   }
   1723   base::i18n::AdjustStringForLocaleDirection(&localized_name);
   1724   name_ = UTF16ToUTF8(localized_name);
   1725 
   1726   // Initialize description (if present).
   1727   if (source.HasKey(keys::kDescription)) {
   1728     if (!source.GetString(keys::kDescription,
   1729                           &description_)) {
   1730       *error = errors::kInvalidDescription;
   1731       return false;
   1732     }
   1733   }
   1734 
   1735   // Initialize homepage url (if present).
   1736   if (source.HasKey(keys::kHomepageURL)) {
   1737     std::string tmp;
   1738     if (!source.GetString(keys::kHomepageURL, &tmp)) {
   1739       *error = ExtensionErrorUtils::FormatErrorMessage(
   1740           errors::kInvalidHomepageURL, "");
   1741       return false;
   1742     }
   1743     homepage_url_ = GURL(tmp);
   1744     if (!homepage_url_.is_valid()) {
   1745       *error = ExtensionErrorUtils::FormatErrorMessage(
   1746           errors::kInvalidHomepageURL, tmp);
   1747       return false;
   1748     }
   1749   }
   1750 
   1751   // Initialize update url (if present).
   1752   if (source.HasKey(keys::kUpdateURL)) {
   1753     std::string tmp;
   1754     if (!source.GetString(keys::kUpdateURL, &tmp)) {
   1755       *error = ExtensionErrorUtils::FormatErrorMessage(
   1756           errors::kInvalidUpdateURL, "");
   1757       return false;
   1758     }
   1759     update_url_ = GURL(tmp);
   1760     if (!update_url_.is_valid() ||
   1761         update_url_.has_ref()) {
   1762       *error = ExtensionErrorUtils::FormatErrorMessage(
   1763           errors::kInvalidUpdateURL, tmp);
   1764       return false;
   1765     }
   1766   }
   1767 
   1768   // Validate minimum Chrome version (if present). We don't need to store this,
   1769   // since the extension is not valid if it is incorrect.
   1770   if (source.HasKey(keys::kMinimumChromeVersion)) {
   1771     std::string minimum_version_string;
   1772     if (!source.GetString(keys::kMinimumChromeVersion,
   1773                           &minimum_version_string)) {
   1774       *error = errors::kInvalidMinimumChromeVersion;
   1775       return false;
   1776     }
   1777 
   1778     scoped_ptr<Version> minimum_version(
   1779         Version::GetVersionFromString(minimum_version_string));
   1780     if (!minimum_version.get()) {
   1781       *error = errors::kInvalidMinimumChromeVersion;
   1782       return false;
   1783     }
   1784 
   1785     chrome::VersionInfo current_version_info;
   1786     if (!current_version_info.is_valid()) {
   1787       NOTREACHED();
   1788       return false;
   1789     }
   1790 
   1791     scoped_ptr<Version> current_version(
   1792         Version::GetVersionFromString(current_version_info.Version()));
   1793     if (!current_version.get()) {
   1794       DCHECK(false);
   1795       return false;
   1796     }
   1797 
   1798     if (current_version->CompareTo(*minimum_version) < 0) {
   1799       *error = ExtensionErrorUtils::FormatErrorMessage(
   1800           errors::kChromeVersionTooLow,
   1801           l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
   1802           minimum_version_string);
   1803       return false;
   1804     }
   1805   }
   1806 
   1807   // Initialize converted_from_user_script (if present)
   1808   source.GetBoolean(keys::kConvertedFromUserScript,
   1809                     &converted_from_user_script_);
   1810 
   1811   // Initialize icons (if present).
   1812   if (source.HasKey(keys::kIcons)) {
   1813     DictionaryValue* icons_value = NULL;
   1814     if (!source.GetDictionary(keys::kIcons, &icons_value)) {
   1815       *error = errors::kInvalidIcons;
   1816       return false;
   1817     }
   1818 
   1819     for (size_t i = 0; i < arraysize(kIconSizes); ++i) {
   1820       std::string key = base::IntToString(kIconSizes[i]);
   1821       if (icons_value->HasKey(key)) {
   1822         std::string icon_path;
   1823         if (!icons_value->GetString(key, &icon_path)) {
   1824           *error = ExtensionErrorUtils::FormatErrorMessage(
   1825               errors::kInvalidIconPath, key);
   1826           return false;
   1827         }
   1828 
   1829         if (!icon_path.empty() && icon_path[0] == '/')
   1830           icon_path = icon_path.substr(1);
   1831 
   1832         if (icon_path.empty()) {
   1833           *error = ExtensionErrorUtils::FormatErrorMessage(
   1834               errors::kInvalidIconPath, key);
   1835           return false;
   1836         }
   1837 
   1838         icons_.Add(kIconSizes[i], icon_path);
   1839       }
   1840     }
   1841   }
   1842 
   1843   // Initialize themes (if present).
   1844   is_theme_ = false;
   1845   if (source.HasKey(keys::kTheme)) {
   1846     // Themes cannot contain extension keys.
   1847     if (ContainsNonThemeKeys(source)) {
   1848       *error = errors::kThemesCannotContainExtensions;
   1849       return false;
   1850     }
   1851 
   1852     DictionaryValue* theme_value = NULL;
   1853     if (!source.GetDictionary(keys::kTheme, &theme_value)) {
   1854       *error = errors::kInvalidTheme;
   1855       return false;
   1856     }
   1857     is_theme_ = true;
   1858 
   1859     DictionaryValue* images_value = NULL;
   1860     if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
   1861       // Validate that the images are all strings
   1862       for (DictionaryValue::key_iterator iter = images_value->begin_keys();
   1863            iter != images_value->end_keys(); ++iter) {
   1864         std::string val;
   1865         if (!images_value->GetString(*iter, &val)) {
   1866           *error = errors::kInvalidThemeImages;
   1867           return false;
   1868         }
   1869       }
   1870       theme_images_.reset(images_value->DeepCopy());
   1871     }
   1872 
   1873     DictionaryValue* colors_value = NULL;
   1874     if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
   1875       // Validate that the colors are RGB or RGBA lists
   1876       for (DictionaryValue::key_iterator iter = colors_value->begin_keys();
   1877            iter != colors_value->end_keys(); ++iter) {
   1878         ListValue* color_list = NULL;
   1879         double alpha = 0.0;
   1880         int alpha_int = 0;
   1881         int color = 0;
   1882         // The color must be a list
   1883         if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) ||
   1884             // And either 3 items (RGB) or 4 (RGBA)
   1885             ((color_list->GetSize() != 3) &&
   1886              ((color_list->GetSize() != 4) ||
   1887               // For RGBA, the fourth item must be a real or int alpha value
   1888               (!color_list->GetDouble(3, &alpha) &&
   1889                !color_list->GetInteger(3, &alpha_int)))) ||
   1890             // For both RGB and RGBA, the first three items must be ints (R,G,B)
   1891             !color_list->GetInteger(0, &color) ||
   1892             !color_list->GetInteger(1, &color) ||
   1893             !color_list->GetInteger(2, &color)) {
   1894           *error = errors::kInvalidThemeColors;
   1895           return false;
   1896         }
   1897       }
   1898       theme_colors_.reset(colors_value->DeepCopy());
   1899     }
   1900 
   1901     DictionaryValue* tints_value = NULL;
   1902     if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) {
   1903       // Validate that the tints are all reals.
   1904       for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
   1905            iter != tints_value->end_keys(); ++iter) {
   1906         ListValue* tint_list = NULL;
   1907         double v = 0.0;
   1908         int vi = 0;
   1909         if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) ||
   1910             tint_list->GetSize() != 3 ||
   1911             !(tint_list->GetDouble(0, &v) || tint_list->GetInteger(0, &vi)) ||
   1912             !(tint_list->GetDouble(1, &v) || tint_list->GetInteger(1, &vi)) ||
   1913             !(tint_list->GetDouble(2, &v) || tint_list->GetInteger(2, &vi))) {
   1914           *error = errors::kInvalidThemeTints;
   1915           return false;
   1916         }
   1917       }
   1918       theme_tints_.reset(tints_value->DeepCopy());
   1919     }
   1920 
   1921     DictionaryValue* display_properties_value = NULL;
   1922     if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
   1923         &display_properties_value)) {
   1924       theme_display_properties_.reset(
   1925           display_properties_value->DeepCopy());
   1926     }
   1927 
   1928     return true;
   1929   }
   1930 
   1931   // Initialize plugins (optional).
   1932   if (source.HasKey(keys::kPlugins)) {
   1933     ListValue* list_value = NULL;
   1934     if (!source.GetList(keys::kPlugins, &list_value)) {
   1935       *error = errors::kInvalidPlugins;
   1936       return false;
   1937     }
   1938 
   1939     for (size_t i = 0; i < list_value->GetSize(); ++i) {
   1940       DictionaryValue* plugin_value = NULL;
   1941       std::string path_str;
   1942       bool is_public = false;
   1943 
   1944       if (!list_value->GetDictionary(i, &plugin_value)) {
   1945         *error = errors::kInvalidPlugins;
   1946         return false;
   1947       }
   1948 
   1949       // Get plugins[i].path.
   1950       if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
   1951         *error = ExtensionErrorUtils::FormatErrorMessage(
   1952             errors::kInvalidPluginsPath, base::IntToString(i));
   1953         return false;
   1954       }
   1955 
   1956       // Get plugins[i].content (optional).
   1957       if (plugin_value->HasKey(keys::kPluginsPublic)) {
   1958         if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
   1959           *error = ExtensionErrorUtils::FormatErrorMessage(
   1960               errors::kInvalidPluginsPublic, base::IntToString(i));
   1961           return false;
   1962         }
   1963       }
   1964 
   1965       // We don't allow extension plugins to run on Chrome OS. We still
   1966       // parse the manifest entry so that error messages are consistently
   1967       // displayed across platforms.
   1968 #if !defined(OS_CHROMEOS)
   1969       plugins_.push_back(PluginInfo());
   1970       plugins_.back().path = path().AppendASCII(path_str);
   1971       plugins_.back().is_public = is_public;
   1972 #endif
   1973     }
   1974   }
   1975 
   1976   if (CommandLine::ForCurrentProcess()->HasSwitch(
   1977           switches::kEnableExperimentalExtensionApis) &&
   1978       source.HasKey(keys::kNaClModules)) {
   1979     ListValue* list_value = NULL;
   1980     if (!source.GetList(keys::kNaClModules, &list_value)) {
   1981       *error = errors::kInvalidNaClModules;
   1982       return false;
   1983     }
   1984 
   1985     for (size_t i = 0; i < list_value->GetSize(); ++i) {
   1986       DictionaryValue* module_value = NULL;
   1987       std::string path_str;
   1988       std::string mime_type;
   1989 
   1990       if (!list_value->GetDictionary(i, &module_value)) {
   1991         *error = errors::kInvalidNaClModules;
   1992         return false;
   1993       }
   1994 
   1995       // Get nacl_modules[i].path.
   1996       if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
   1997         *error = ExtensionErrorUtils::FormatErrorMessage(
   1998             errors::kInvalidNaClModulesPath, base::IntToString(i));
   1999         return false;
   2000       }
   2001 
   2002       // Get nacl_modules[i].mime_type.
   2003       if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
   2004         *error = ExtensionErrorUtils::FormatErrorMessage(
   2005             errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
   2006         return false;
   2007       }
   2008 
   2009       nacl_modules_.push_back(NaClModuleInfo());
   2010       nacl_modules_.back().url = GetResourceURL(path_str);
   2011       nacl_modules_.back().mime_type = mime_type;
   2012     }
   2013   }
   2014 
   2015   // Initialize toolstrips.  This is deprecated for public use.
   2016   // NOTE(erikkay) Although deprecated, we intend to preserve this parsing
   2017   // code indefinitely.  Please contact me or Joi for details as to why.
   2018   if (CommandLine::ForCurrentProcess()->HasSwitch(
   2019           switches::kEnableExperimentalExtensionApis) &&
   2020       source.HasKey(keys::kToolstrips)) {
   2021     ListValue* list_value = NULL;
   2022     if (!source.GetList(keys::kToolstrips, &list_value)) {
   2023       *error = errors::kInvalidToolstrips;
   2024       return false;
   2025     }
   2026 
   2027     for (size_t i = 0; i < list_value->GetSize(); ++i) {
   2028       GURL toolstrip;
   2029       DictionaryValue* toolstrip_value = NULL;
   2030       std::string toolstrip_path;
   2031       if (list_value->GetString(i, &toolstrip_path)) {
   2032         // Support a simple URL value for backwards compatibility.
   2033         toolstrip = GetResourceURL(toolstrip_path);
   2034       } else if (list_value->GetDictionary(i, &toolstrip_value)) {
   2035         if (!toolstrip_value->GetString(keys::kToolstripPath,
   2036                                         &toolstrip_path)) {
   2037           *error = ExtensionErrorUtils::FormatErrorMessage(
   2038               errors::kInvalidToolstrip, base::IntToString(i));
   2039           return false;
   2040         }
   2041         toolstrip = GetResourceURL(toolstrip_path);
   2042       } else {
   2043         *error = ExtensionErrorUtils::FormatErrorMessage(
   2044             errors::kInvalidToolstrip, base::IntToString(i));
   2045         return false;
   2046       }
   2047       toolstrips_.push_back(toolstrip);
   2048     }
   2049   }
   2050 
   2051   // Initialize content scripts (optional).
   2052   if (source.HasKey(keys::kContentScripts)) {
   2053     ListValue* list_value;
   2054     if (!source.GetList(keys::kContentScripts, &list_value)) {
   2055       *error = errors::kInvalidContentScriptsList;
   2056       return false;
   2057     }
   2058 
   2059     for (size_t i = 0; i < list_value->GetSize(); ++i) {
   2060       DictionaryValue* content_script = NULL;
   2061       if (!list_value->GetDictionary(i, &content_script)) {
   2062         *error = ExtensionErrorUtils::FormatErrorMessage(
   2063             errors::kInvalidContentScript, base::IntToString(i));
   2064         return false;
   2065       }
   2066 
   2067       UserScript script;
   2068       if (!LoadUserScriptHelper(content_script, i, flags, error, &script))
   2069         return false;  // Failed to parse script context definition.
   2070       script.set_extension_id(id());
   2071       if (converted_from_user_script_) {
   2072         script.set_emulate_greasemonkey(true);
   2073         script.set_match_all_frames(true);  // Greasemonkey matches all frames.
   2074       }
   2075       content_scripts_.push_back(script);
   2076     }
   2077   }
   2078 
   2079   // Initialize page action (optional).
   2080   DictionaryValue* page_action_value = NULL;
   2081 
   2082   if (source.HasKey(keys::kPageActions)) {
   2083     ListValue* list_value = NULL;
   2084     if (!source.GetList(keys::kPageActions, &list_value)) {
   2085       *error = errors::kInvalidPageActionsList;
   2086       return false;
   2087     }
   2088 
   2089     size_t list_value_length = list_value->GetSize();
   2090 
   2091     if (list_value_length == 0u) {
   2092       // A list with zero items is allowed, and is equivalent to not having
   2093       // a page_actions key in the manifest.  Don't set |page_action_value|.
   2094     } else if (list_value_length == 1u) {
   2095       if (!list_value->GetDictionary(0, &page_action_value)) {
   2096         *error = errors::kInvalidPageAction;
   2097         return false;
   2098       }
   2099     } else {  // list_value_length > 1u.
   2100       *error = errors::kInvalidPageActionsListSize;
   2101       return false;
   2102     }
   2103   } else if (source.HasKey(keys::kPageAction)) {
   2104     if (!source.GetDictionary(keys::kPageAction, &page_action_value)) {
   2105       *error = errors::kInvalidPageAction;
   2106       return false;
   2107     }
   2108   }
   2109 
   2110   // If page_action_value is not NULL, then there was a valid page action.
   2111   if (page_action_value) {
   2112     page_action_.reset(
   2113         LoadExtensionActionHelper(page_action_value, error));
   2114     if (!page_action_.get())
   2115       return false;  // Failed to parse page action definition.
   2116   }
   2117 
   2118   // Initialize browser action (optional).
   2119   if (source.HasKey(keys::kBrowserAction)) {
   2120     DictionaryValue* browser_action_value = NULL;
   2121     if (!source.GetDictionary(keys::kBrowserAction, &browser_action_value)) {
   2122       *error = errors::kInvalidBrowserAction;
   2123       return false;
   2124     }
   2125 
   2126     browser_action_.reset(
   2127         LoadExtensionActionHelper(browser_action_value, error));
   2128     if (!browser_action_.get())
   2129       return false;  // Failed to parse browser action definition.
   2130   }
   2131 
   2132   // Initialize file browser actions (optional).
   2133   if (source.HasKey(keys::kFileBrowserHandlers)) {
   2134     ListValue* file_browser_handlers_value = NULL;
   2135     if (!source.GetList(keys::kFileBrowserHandlers,
   2136                               &file_browser_handlers_value)) {
   2137       *error = errors::kInvalidFileBrowserHandler;
   2138       return false;
   2139     }
   2140 
   2141     file_browser_handlers_.reset(
   2142         LoadFileBrowserHandlers(file_browser_handlers_value, error));
   2143     if (!file_browser_handlers_.get())
   2144       return false;  // Failed to parse file browser actions definition.
   2145   }
   2146 
   2147   // Load App settings.
   2148   if (!LoadIsApp(manifest_value_.get(), error) ||
   2149       !LoadExtent(manifest_value_.get(), keys::kWebURLs,
   2150                   &extent_,
   2151                   errors::kInvalidWebURLs, errors::kInvalidWebURL,
   2152                   parse_strictness, error) ||
   2153       !EnsureNotHybridApp(manifest_value_.get(), error) ||
   2154       !LoadLaunchURL(manifest_value_.get(), error) ||
   2155       !LoadLaunchContainer(manifest_value_.get(), error) ||
   2156       !LoadAppIsolation(manifest_value_.get(), error)) {
   2157     return false;
   2158   }
   2159 
   2160   // Initialize options page url (optional).
   2161   // Funtion LoadIsApp() set is_app_ above.
   2162   if (source.HasKey(keys::kOptionsPage)) {
   2163     std::string options_str;
   2164     if (!source.GetString(keys::kOptionsPage, &options_str)) {
   2165       *error = errors::kInvalidOptionsPage;
   2166       return false;
   2167     }
   2168 
   2169     if (is_hosted_app()) {
   2170       // hosted apps require an absolute URL.
   2171       GURL options_url(options_str);
   2172       if (!options_url.is_valid() ||
   2173           !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) {
   2174         *error = errors::kInvalidOptionsPageInHostedApp;
   2175         return false;
   2176       }
   2177       options_url_ = options_url;
   2178     } else {
   2179       GURL absolute(options_str);
   2180       if (absolute.is_valid()) {
   2181         *error = errors::kInvalidOptionsPageExpectUrlInPackage;
   2182         return false;
   2183       }
   2184       options_url_ = GetResourceURL(options_str);
   2185       if (!options_url_.is_valid()) {
   2186         *error = errors::kInvalidOptionsPage;
   2187         return false;
   2188       }
   2189     }
   2190   }
   2191 
   2192   // Initialize the permissions (optional).
   2193   if (source.HasKey(keys::kPermissions)) {
   2194     ListValue* permissions = NULL;
   2195     if (!source.GetList(keys::kPermissions, &permissions)) {
   2196       *error = ExtensionErrorUtils::FormatErrorMessage(
   2197           errors::kInvalidPermissions, "");
   2198       return false;
   2199     }
   2200 
   2201     for (size_t i = 0; i < permissions->GetSize(); ++i) {
   2202       std::string permission_str;
   2203       if (!permissions->GetString(i, &permission_str)) {
   2204         *error = ExtensionErrorUtils::FormatErrorMessage(
   2205             errors::kInvalidPermission, base::IntToString(i));
   2206         return false;
   2207       }
   2208 
   2209       // Only COMPONENT extensions can use private APIs.
   2210       // TODO(asargent) - We want a more general purpose mechanism for this,
   2211       // and better error messages. (http://crbug.com/54013)
   2212       if (!IsComponentOnlyPermission(permission_str)
   2213 #ifndef NDEBUG
   2214            && !CommandLine::ForCurrentProcess()->HasSwitch(
   2215                  switches::kExposePrivateExtensionApi)
   2216 #endif
   2217           ) {
   2218         continue;
   2219       }
   2220 
   2221       // Remap the old unlimited storage permission name.
   2222       if (permission_str == kOldUnlimitedStoragePermission)
   2223         permission_str = kUnlimitedStoragePermission;
   2224 
   2225       if (web_extent().is_empty() || location() == Extension::COMPONENT) {
   2226         // Check if it's a module permission.  If so, enable that permission.
   2227         if (IsAPIPermission(permission_str)) {
   2228           // Only allow the experimental API permission if the command line
   2229           // flag is present, or if the extension is a component of Chrome.
   2230           if (permission_str == Extension::kExperimentalPermission &&
   2231               !CommandLine::ForCurrentProcess()->HasSwitch(
   2232                 switches::kEnableExperimentalExtensionApis) &&
   2233               location() != Extension::COMPONENT) {
   2234             *error = errors::kExperimentalFlagRequired;
   2235             return false;
   2236           }
   2237           api_permissions_.insert(permission_str);
   2238           continue;
   2239         }
   2240       } else {
   2241         // Hosted apps only get access to a subset of the valid permissions.
   2242         if (IsHostedAppPermission(permission_str)) {
   2243           api_permissions_.insert(permission_str);
   2244           continue;
   2245         }
   2246       }
   2247 
   2248       // Check if it's a host pattern permission.
   2249       URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ?
   2250           URLPattern::SCHEME_ALL : kValidHostPermissionSchemes);
   2251 
   2252       URLPattern::ParseResult parse_result = pattern.Parse(permission_str,
   2253                                                            parse_strictness);
   2254       if (parse_result == URLPattern::PARSE_SUCCESS) {
   2255         if (!CanSpecifyHostPermission(pattern)) {
   2256           *error = ExtensionErrorUtils::FormatErrorMessage(
   2257               errors::kInvalidPermissionScheme, base::IntToString(i));
   2258           return false;
   2259         }
   2260 
   2261         // The path component is not used for host permissions, so we force it
   2262         // to match all paths.
   2263         pattern.SetPath("/*");
   2264 
   2265         if (pattern.MatchesScheme(chrome::kFileScheme) &&
   2266             !CanExecuteScriptEverywhere()) {
   2267           wants_file_access_ = true;
   2268           if (!(flags & ALLOW_FILE_ACCESS))
   2269             pattern.set_valid_schemes(
   2270                 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
   2271         }
   2272 
   2273         host_permissions_.push_back(pattern);
   2274       }
   2275 
   2276       // If it's not a host permission, then it's probably an unknown API
   2277       // permission. Do not throw an error so extensions can retain
   2278       // backwards compatability (http://crbug.com/42742).
   2279       // TODO(jstritar): We can improve error messages by adding better
   2280       // validation of API permissions here.
   2281       // TODO(skerner): Consider showing the reason |permission_str| is not
   2282       // a valid URL pattern if it is almost valid.  For example, if it has
   2283       // a valid scheme, and failed to parse because it has a port, show an
   2284       // error.
   2285     }
   2286   }
   2287 
   2288   // Initialize background url (optional).
   2289   if (source.HasKey(keys::kBackground)) {
   2290     std::string background_str;
   2291     if (!source.GetString(keys::kBackground, &background_str)) {
   2292       *error = errors::kInvalidBackground;
   2293       return false;
   2294     }
   2295 
   2296     if (is_hosted_app()) {
   2297       // Make sure "background" permission is set.
   2298       if (api_permissions_.find(kBackgroundPermission) ==
   2299           api_permissions_.end()) {
   2300         *error = errors::kBackgroundPermissionNeeded;
   2301         return false;
   2302       }
   2303       // Hosted apps require an absolute URL.
   2304       GURL bg_page(background_str);
   2305       if (!bg_page.is_valid()) {
   2306         *error = errors::kInvalidBackgroundInHostedApp;
   2307         return false;
   2308       }
   2309 
   2310       if (!(bg_page.SchemeIs("https") ||
   2311            (CommandLine::ForCurrentProcess()->HasSwitch(
   2312                 switches::kAllowHTTPBackgroundPage) &&
   2313             bg_page.SchemeIs("http")))) {
   2314         *error = errors::kInvalidBackgroundInHostedApp;
   2315         return false;
   2316       }
   2317       background_url_ = bg_page;
   2318     } else {
   2319       background_url_ = GetResourceURL(background_str);
   2320     }
   2321   }
   2322 
   2323   if (source.HasKey(keys::kDefaultLocale)) {
   2324     if (!source.GetString(keys::kDefaultLocale, &default_locale_) ||
   2325         !l10n_util::IsValidLocaleSyntax(default_locale_)) {
   2326       *error = errors::kInvalidDefaultLocale;
   2327       return false;
   2328     }
   2329   }
   2330 
   2331   // Chrome URL overrides (optional)
   2332   if (source.HasKey(keys::kChromeURLOverrides)) {
   2333     DictionaryValue* overrides = NULL;
   2334     if (!source.GetDictionary(keys::kChromeURLOverrides, &overrides)) {
   2335       *error = errors::kInvalidChromeURLOverrides;
   2336       return false;
   2337     }
   2338 
   2339     // Validate that the overrides are all strings
   2340     for (DictionaryValue::key_iterator iter = overrides->begin_keys();
   2341          iter != overrides->end_keys(); ++iter) {
   2342       std::string page = *iter;
   2343       std::string val;
   2344       // Restrict override pages to a list of supported URLs.
   2345       if ((page != chrome::kChromeUINewTabHost &&
   2346 #if defined(TOUCH_UI)
   2347            page != chrome::kChromeUIKeyboardHost &&
   2348 #endif
   2349 #if defined(OS_CHROMEOS)
   2350            page != chrome::kChromeUIActivationMessageHost &&
   2351 #endif
   2352            page != chrome::kChromeUIBookmarksHost &&
   2353            page != chrome::kChromeUIHistoryHost) ||
   2354           !overrides->GetStringWithoutPathExpansion(*iter, &val)) {
   2355         *error = errors::kInvalidChromeURLOverrides;
   2356         return false;
   2357       }
   2358       // Replace the entry with a fully qualified chrome-extension:// URL.
   2359       chrome_url_overrides_[page] = GetResourceURL(val);
   2360     }
   2361 
   2362     // An extension may override at most one page.
   2363     if (overrides->size() > 1) {
   2364       *error = errors::kMultipleOverrides;
   2365       return false;
   2366     }
   2367   }
   2368 
   2369   if (source.HasKey(keys::kOmnibox)) {
   2370     if (!source.GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
   2371         omnibox_keyword_.empty()) {
   2372       *error = errors::kInvalidOmniboxKeyword;
   2373       return false;
   2374     }
   2375   }
   2376 
   2377   // Initialize devtools page url (optional).
   2378   if (source.HasKey(keys::kDevToolsPage)) {
   2379     std::string devtools_str;
   2380     if (!source.GetString(keys::kDevToolsPage, &devtools_str)) {
   2381       *error = errors::kInvalidDevToolsPage;
   2382       return false;
   2383     }
   2384     if (!HasApiPermission(Extension::kExperimentalPermission)) {
   2385       *error = errors::kDevToolsExperimental;
   2386       return false;
   2387     }
   2388     devtools_url_ = GetResourceURL(devtools_str);
   2389   }
   2390 
   2391   // Initialize sidebar action (optional).
   2392   if (source.HasKey(keys::kSidebar)) {
   2393     DictionaryValue* sidebar_value = NULL;
   2394     if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) {
   2395       *error = errors::kInvalidSidebar;
   2396       return false;
   2397     }
   2398     if (!HasApiPermission(Extension::kExperimentalPermission)) {
   2399       *error = errors::kSidebarExperimental;
   2400       return false;
   2401     }
   2402     sidebar_defaults_.reset(LoadExtensionSidebarDefaults(sidebar_value, error));
   2403     if (!sidebar_defaults_.get())
   2404       return false;  // Failed to parse sidebar definition.
   2405   }
   2406 
   2407   // Initialize text-to-speech voices (optional).
   2408   if (source.HasKey(keys::kTts)) {
   2409     DictionaryValue* tts_dict = NULL;
   2410     if (!source.GetDictionary(keys::kTts, &tts_dict)) {
   2411       *error = errors::kInvalidTts;
   2412       return false;
   2413     }
   2414 
   2415     if (tts_dict->HasKey(keys::kTtsVoices)) {
   2416       ListValue* tts_voices = NULL;
   2417       if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
   2418         *error = errors::kInvalidTtsVoices;
   2419         return false;
   2420       }
   2421 
   2422       for (size_t i = 0; i < tts_voices->GetSize(); i++) {
   2423         DictionaryValue* one_tts_voice = NULL;
   2424         if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
   2425           *error = errors::kInvalidTtsVoices;
   2426           return false;
   2427         }
   2428 
   2429         TtsVoice voice_data;
   2430         if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
   2431           if (!one_tts_voice->GetString(
   2432                   keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
   2433             *error = errors::kInvalidTtsVoicesVoiceName;
   2434             return false;
   2435           }
   2436         }
   2437         if (one_tts_voice->HasKey(keys::kTtsVoicesLocale)) {
   2438           if (!one_tts_voice->GetString(
   2439                   keys::kTtsVoicesLocale, &voice_data.locale) ||
   2440               !l10n_util::IsValidLocaleSyntax(voice_data.locale)) {
   2441             *error = errors::kInvalidTtsVoicesLocale;
   2442             return false;
   2443           }
   2444         }
   2445         if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
   2446           if (!one_tts_voice->GetString(
   2447                   keys::kTtsVoicesGender, &voice_data.gender) ||
   2448               (voice_data.gender != keys::kTtsGenderMale &&
   2449                voice_data.gender != keys::kTtsGenderFemale)) {
   2450             *error = errors::kInvalidTtsVoicesGender;
   2451             return false;
   2452           }
   2453         }
   2454 
   2455         tts_voices_.push_back(voice_data);
   2456       }
   2457     }
   2458   }
   2459 
   2460   // Initialize incognito behavior. Apps default to split mode, extensions
   2461   // default to spanning.
   2462   incognito_split_mode_ = is_app();
   2463   if (source.HasKey(keys::kIncognito)) {
   2464     std::string value;
   2465     if (!source.GetString(keys::kIncognito, &value)) {
   2466       *error = errors::kInvalidIncognitoBehavior;
   2467       return false;
   2468     }
   2469     if (value == values::kIncognitoSpanning) {
   2470       incognito_split_mode_ = false;
   2471     } else if (value == values::kIncognitoSplit) {
   2472       incognito_split_mode_ = true;
   2473     } else {
   2474       *error = errors::kInvalidIncognitoBehavior;
   2475       return false;
   2476     }
   2477   }
   2478 
   2479   if (HasMultipleUISurfaces()) {
   2480     *error = errors::kOneUISurfaceOnly;
   2481     return false;
   2482   }
   2483 
   2484   InitEffectiveHostPermissions();
   2485 
   2486   // Although |source| is passed in as a const, it's still possible to modify
   2487   // it.  This is dangerous since the utility process re-uses |source| after
   2488   // it calls InitFromValue, passing it up to the browser process which calls
   2489   // InitFromValue again.  As a result, we need to make sure that nobody
   2490   // accidentally modifies it.
   2491   DCHECK(source.Equals(manifest_value_.get()));
   2492 
   2493   return true;
   2494 }
   2495 
   2496 // static
   2497 std::string Extension::ChromeStoreLaunchURL() {
   2498   std::string gallery_prefix = extension_urls::kGalleryBrowsePrefix;
   2499   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsGalleryURL))
   2500     gallery_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
   2501         switches::kAppsGalleryURL);
   2502   if (EndsWith(gallery_prefix, "/", true))
   2503     gallery_prefix = gallery_prefix.substr(0, gallery_prefix.length() - 1);
   2504   return gallery_prefix;
   2505 }
   2506 
   2507 GURL Extension::GetHomepageURL() const {
   2508   if (homepage_url_.is_valid())
   2509     return homepage_url_;
   2510 
   2511   if (!UpdatesFromGallery())
   2512     return GURL();
   2513 
   2514   // TODO(erikkay): This may not be entirely correct with the webstore.
   2515   // I think it will have a mixture of /extensions/detail and /webstore/detail
   2516   // URLs.  Perhaps they'll handle this nicely with redirects?
   2517   GURL url(ChromeStoreLaunchURL() + std::string("/detail/") + id());
   2518   return url;
   2519 }
   2520 
   2521 std::set<FilePath> Extension::GetBrowserImages() const {
   2522   std::set<FilePath> image_paths;
   2523   // TODO(viettrungluu): These |FilePath::FromWStringHack(UTF8ToWide())|
   2524   // indicate that we're doing something wrong.
   2525 
   2526   // Extension icons.
   2527   for (ExtensionIconSet::IconMap::const_iterator iter = icons().map().begin();
   2528        iter != icons().map().end(); ++iter) {
   2529     image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
   2530   }
   2531 
   2532   // Theme images.
   2533   DictionaryValue* theme_images = GetThemeImages();
   2534   if (theme_images) {
   2535     for (DictionaryValue::key_iterator it = theme_images->begin_keys();
   2536          it != theme_images->end_keys(); ++it) {
   2537       std::string val;
   2538       if (theme_images->GetStringWithoutPathExpansion(*it, &val))
   2539         image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(val)));
   2540     }
   2541   }
   2542 
   2543   // Page action icons.
   2544   if (page_action()) {
   2545     std::vector<std::string>* icon_paths = page_action()->icon_paths();
   2546     for (std::vector<std::string>::iterator iter = icon_paths->begin();
   2547          iter != icon_paths->end(); ++iter) {
   2548       image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(*iter)));
   2549     }
   2550   }
   2551 
   2552   // Browser action icons.
   2553   if (browser_action()) {
   2554     std::vector<std::string>* icon_paths = browser_action()->icon_paths();
   2555     for (std::vector<std::string>::iterator iter = icon_paths->begin();
   2556          iter != icon_paths->end(); ++iter) {
   2557       image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(*iter)));
   2558     }
   2559   }
   2560 
   2561   return image_paths;
   2562 }
   2563 
   2564 GURL Extension::GetFullLaunchURL() const {
   2565   if (!launch_local_path().empty())
   2566     return url().Resolve(launch_local_path());
   2567   else
   2568     return GURL(launch_web_url());
   2569 }
   2570 
   2571 static std::string SizeToString(const gfx::Size& max_size) {
   2572   return base::IntToString(max_size.width()) + "x" +
   2573          base::IntToString(max_size.height());
   2574 }
   2575 
   2576 // static
   2577 void Extension::SetScriptingWhitelist(
   2578     const Extension::ScriptingWhitelist& whitelist) {
   2579   ScriptingWhitelist* current_whitelist =
   2580       ExtensionConfig::GetInstance()->whitelist();
   2581   current_whitelist->clear();
   2582   for (ScriptingWhitelist::const_iterator it = whitelist.begin();
   2583        it != whitelist.end(); ++it) {
   2584     current_whitelist->push_back(*it);
   2585   }
   2586 }
   2587 
   2588 // static
   2589 const Extension::ScriptingWhitelist* Extension::GetScriptingWhitelist() {
   2590   return ExtensionConfig::GetInstance()->whitelist();
   2591 }
   2592 
   2593 void Extension::SetCachedImage(const ExtensionResource& source,
   2594                                const SkBitmap& image,
   2595                                const gfx::Size& original_size) const {
   2596   DCHECK(source.extension_root() == path());  // The resource must come from
   2597                                               // this extension.
   2598   const FilePath& path = source.relative_path();
   2599   gfx::Size actual_size(image.width(), image.height());
   2600   if (actual_size == original_size) {
   2601     image_cache_[ImageCacheKey(path, std::string())] = image;
   2602   } else {
   2603     image_cache_[ImageCacheKey(path, SizeToString(actual_size))] = image;
   2604   }
   2605 }
   2606 
   2607 bool Extension::HasCachedImage(const ExtensionResource& source,
   2608                                const gfx::Size& max_size) const {
   2609   DCHECK(source.extension_root() == path());  // The resource must come from
   2610                                               // this extension.
   2611   return GetCachedImageImpl(source, max_size) != NULL;
   2612 }
   2613 
   2614 SkBitmap Extension::GetCachedImage(const ExtensionResource& source,
   2615                                    const gfx::Size& max_size) const {
   2616   DCHECK(source.extension_root() == path());  // The resource must come from
   2617                                               // this extension.
   2618   SkBitmap* image = GetCachedImageImpl(source, max_size);
   2619   return image ? *image : SkBitmap();
   2620 }
   2621 
   2622 SkBitmap* Extension::GetCachedImageImpl(const ExtensionResource& source,
   2623                                         const gfx::Size& max_size) const {
   2624   const FilePath& path = source.relative_path();
   2625 
   2626   // Look for exact size match.
   2627   ImageCache::iterator i = image_cache_.find(
   2628       ImageCacheKey(path, SizeToString(max_size)));
   2629   if (i != image_cache_.end())
   2630     return &(i->second);
   2631 
   2632   // If we have the original size version cached, return that if it's small
   2633   // enough.
   2634   i = image_cache_.find(ImageCacheKey(path, std::string()));
   2635   if (i != image_cache_.end()) {
   2636     SkBitmap& image = i->second;
   2637     if (image.width() <= max_size.width() &&
   2638         image.height() <= max_size.height())
   2639       return &(i->second);
   2640   }
   2641 
   2642   return NULL;
   2643 }
   2644 
   2645 ExtensionResource Extension::GetIconResource(
   2646     int size, ExtensionIconSet::MatchType match_type) const {
   2647   std::string path = icons().Get(size, match_type);
   2648   if (path.empty())
   2649     return ExtensionResource();
   2650   return GetResource(path);
   2651 }
   2652 
   2653 GURL Extension::GetIconURL(int size,
   2654                            ExtensionIconSet::MatchType match_type) const {
   2655   std::string path = icons().Get(size, match_type);
   2656   if (path.empty())
   2657     return GURL();
   2658   else
   2659     return GetResourceURL(path);
   2660 }
   2661 
   2662 bool Extension::CanSpecifyHostPermission(const URLPattern& pattern) const {
   2663   if (!pattern.match_all_urls() &&
   2664       pattern.MatchesScheme(chrome::kChromeUIScheme)) {
   2665     // Only allow access to chrome://favicon to regular extensions. Component
   2666     // extensions can have access to all of chrome://*.
   2667     return (pattern.host() == chrome::kChromeUIFaviconHost ||
   2668             CanExecuteScriptEverywhere());
   2669   }
   2670 
   2671   // Otherwise, the valid schemes were handled by URLPattern.
   2672   return true;
   2673 }
   2674 
   2675 // static
   2676 bool Extension::HasApiPermission(
   2677     const std::set<std::string>& api_permissions,
   2678     const std::string& function_name) {
   2679   std::string permission_name = function_name;
   2680 
   2681   for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
   2682     if (permission_name == kNonPermissionFunctionNames[i])
   2683       return true;
   2684   }
   2685 
   2686   // See if this is a function or event name first and strip out the package.
   2687   // Functions will be of the form package.function
   2688   // Events will be of the form package/id or package.optional.stuff
   2689   size_t separator = function_name.find_first_of("./");
   2690   if (separator != std::string::npos)
   2691     permission_name = function_name.substr(0, separator);
   2692 
   2693   // windows and tabs are the same permission.
   2694   if (permission_name == kWindowPermission)
   2695     permission_name = Extension::kTabPermission;
   2696 
   2697   if (api_permissions.count(permission_name))
   2698     return true;
   2699 
   2700   for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) {
   2701     if (permission_name == kNonPermissionModuleNames[i]) {
   2702       return true;
   2703     }
   2704   }
   2705 
   2706   return false;
   2707 }
   2708 
   2709 bool Extension::HasHostPermission(const GURL& url) const {
   2710   for (URLPatternList::const_iterator host = host_permissions().begin();
   2711        host != host_permissions().end(); ++host) {
   2712     // Non-component extensions can only access chrome://favicon and no other
   2713     // chrome:// scheme urls.
   2714     if (url.SchemeIs(chrome::kChromeUIScheme) &&
   2715         url.host() != chrome::kChromeUIFaviconHost &&
   2716         location() != Extension::COMPONENT)
   2717       return false;
   2718 
   2719     if (host->MatchesUrl(url))
   2720       return true;
   2721   }
   2722   return false;
   2723 }
   2724 
   2725 void Extension::InitEffectiveHostPermissions() {
   2726   // Some APIs effectively grant access to every site.  New ones should be
   2727   // added here.  (I'm looking at you, network API)
   2728   if (HasApiPermission(api_permissions_, kProxyPermission) ||
   2729       !devtools_url_.is_empty()) {
   2730     URLPattern all_urls(URLPattern::SCHEME_ALL);
   2731     all_urls.set_match_all_urls(true);
   2732     effective_host_permissions_.AddPattern(all_urls);
   2733     return;
   2734   }
   2735 
   2736   for (URLPatternList::const_iterator host = host_permissions().begin();
   2737        host != host_permissions().end(); ++host)
   2738     effective_host_permissions_.AddPattern(*host);
   2739 
   2740   for (UserScriptList::const_iterator content_script =
   2741            content_scripts().begin();
   2742        content_script != content_scripts().end(); ++content_script) {
   2743     UserScript::PatternList::const_iterator pattern =
   2744         content_script->url_patterns().begin();
   2745     for (; pattern != content_script->url_patterns().end(); ++pattern)
   2746       effective_host_permissions_.AddPattern(*pattern);
   2747   }
   2748 }
   2749 
   2750 bool Extension::IsComponentOnlyPermission
   2751     (const std::string& permission) const {
   2752   if (location() == Extension::COMPONENT)
   2753     return true;
   2754 
   2755   // Non-component extensions are not allowed to access private apis.
   2756   for (size_t i = 0; i < Extension::kNumComponentPrivatePermissions; ++i) {
   2757     if (permission == Extension::kComponentPrivatePermissionNames[i])
   2758       return false;
   2759   }
   2760   return true;
   2761 }
   2762 
   2763 bool Extension::HasMultipleUISurfaces() const {
   2764   int num_surfaces = 0;
   2765 
   2766   if (page_action())
   2767     ++num_surfaces;
   2768 
   2769   if (browser_action())
   2770     ++num_surfaces;
   2771 
   2772   if (is_app())
   2773     ++num_surfaces;
   2774 
   2775   return num_surfaces > 1;
   2776 }
   2777 
   2778 bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
   2779                                        const UserScript* script,
   2780                                        std::string* error) const {
   2781   // The gallery is special-cased as a restricted URL for scripting to prevent
   2782   // access to special JS bindings we expose to the gallery (and avoid things
   2783   // like extensions removing the "report abuse" link).
   2784   // TODO(erikkay): This seems like the wrong test.  Shouldn't we we testing
   2785   // against the store app extent?
   2786   if ((page_url.host() == GURL(Extension::ChromeStoreLaunchURL()).host()) &&
   2787       !CanExecuteScriptEverywhere() &&
   2788       !CommandLine::ForCurrentProcess()->HasSwitch(
   2789           switches::kAllowScriptingGallery)) {
   2790     if (error)
   2791       *error = errors::kCannotScriptGallery;
   2792     return false;
   2793   }
   2794 
   2795   if (page_url.SchemeIs(chrome::kChromeUIScheme) &&
   2796       !CanExecuteScriptEverywhere())
   2797     return false;
   2798 
   2799   // If a script is specified, use its matches.
   2800   if (script)
   2801     return script->MatchesUrl(page_url);
   2802 
   2803   // Otherwise, see if this extension has permission to execute script
   2804   // programmatically on pages.
   2805   for (size_t i = 0; i < host_permissions_.size(); ++i) {
   2806     if (host_permissions_[i].MatchesUrl(page_url))
   2807       return true;
   2808   }
   2809 
   2810   if (error) {
   2811     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
   2812                                                      page_url.spec());
   2813   }
   2814 
   2815   return false;
   2816 }
   2817 
   2818 // static
   2819 bool Extension::HasEffectiveAccessToAllHosts(
   2820     const ExtensionExtent& effective_host_permissions,
   2821     const std::set<std::string>& api_permissions) {
   2822   const URLPatternList patterns = effective_host_permissions.patterns();
   2823   for (URLPatternList::const_iterator host = patterns.begin();
   2824        host != patterns.end(); ++host) {
   2825     if (host->match_all_urls() ||
   2826         (host->match_subdomains() && host->host().empty()))
   2827       return true;
   2828   }
   2829 
   2830   return false;
   2831 }
   2832 
   2833 bool Extension::HasEffectiveAccessToAllHosts() const {
   2834   return HasEffectiveAccessToAllHosts(GetEffectiveHostPermissions(),
   2835                                       api_permissions());
   2836 }
   2837 
   2838 bool Extension::HasFullPermissions() const {
   2839   return !plugins().empty();
   2840 }
   2841 
   2842 bool Extension::ShowConfigureContextMenus() const {
   2843   // Don't show context menu for component extensions. We might want to show
   2844   // options for component extension button but now there is no component
   2845   // extension with options. All other menu items like uninstall have
   2846   // no sense for component extensions.
   2847   return location() != Extension::COMPONENT;
   2848 }
   2849 
   2850 bool Extension::IsAPIPermission(const std::string& str) const {
   2851   for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
   2852     if (str == Extension::kPermissions[i].name) {
   2853       return true;
   2854     }
   2855   }
   2856   return false;
   2857 }
   2858 
   2859 bool Extension::CanExecuteScriptEverywhere() const {
   2860   if (location() == Extension::COMPONENT
   2861 #ifndef NDEBUG
   2862       || CommandLine::ForCurrentProcess()->HasSwitch(
   2863           switches::kExposePrivateExtensionApi)
   2864 #endif
   2865       )
   2866     return true;
   2867 
   2868   ScriptingWhitelist* whitelist =
   2869       ExtensionConfig::GetInstance()->whitelist();
   2870 
   2871   for (ScriptingWhitelist::const_iterator it = whitelist->begin();
   2872        it != whitelist->end(); ++it) {
   2873     if (id() == *it) {
   2874       return true;
   2875     }
   2876   }
   2877 
   2878   return false;
   2879 }
   2880 
   2881 bool Extension::CanCaptureVisiblePage(const GURL& page_url,
   2882                                       std::string *error) const {
   2883   if (HasHostPermission(page_url) || page_url.GetOrigin() == url())
   2884     return true;
   2885 
   2886   if (error) {
   2887     *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
   2888                                                      page_url.spec());
   2889   }
   2890   return false;
   2891 }
   2892 
   2893 bool Extension::UpdatesFromGallery() const {
   2894   return update_url() == GalleryUpdateUrl(false) ||
   2895          update_url() == GalleryUpdateUrl(true);
   2896 }
   2897 
   2898 bool Extension::OverlapsWithOrigin(const GURL& origin) const {
   2899   if (url() == origin)
   2900     return true;
   2901 
   2902   if (web_extent().is_empty())
   2903     return false;
   2904 
   2905   // Note: patterns and extents ignore port numbers.
   2906   URLPattern origin_only_pattern(kValidWebExtentSchemes);
   2907   if (!origin_only_pattern.SetScheme(origin.scheme()))
   2908     return false;
   2909   origin_only_pattern.set_host(origin.host());
   2910   origin_only_pattern.SetPath("/*");
   2911 
   2912   ExtensionExtent origin_only_pattern_list;
   2913   origin_only_pattern_list.AddPattern(origin_only_pattern);
   2914 
   2915   return web_extent().OverlapsWith(origin_only_pattern_list);
   2916 }
   2917 
   2918 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
   2919                              const std::string& id,
   2920                              const FilePath& path,
   2921                              Extension::Location location)
   2922     : extension_id(id),
   2923       extension_path(path),
   2924       extension_location(location) {
   2925   if (manifest)
   2926     extension_manifest.reset(manifest->DeepCopy());
   2927 }
   2928 
   2929 ExtensionInfo::~ExtensionInfo() {}
   2930 
   2931 UninstalledExtensionInfo::UninstalledExtensionInfo(
   2932     const Extension& extension)
   2933     : extension_id(extension.id()),
   2934       extension_api_permissions(extension.api_permissions()),
   2935       extension_type(extension.GetType()),
   2936       update_url(extension.update_url()) {}
   2937 
   2938 UninstalledExtensionInfo::~UninstalledExtensionInfo() {}
   2939 
   2940 
   2941 UnloadedExtensionInfo::UnloadedExtensionInfo(
   2942     const Extension* extension,
   2943     Reason reason)
   2944   : reason(reason),
   2945     already_disabled(false),
   2946     extension(extension) {}
   2947