Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/common/extensions/manifest_url_handler.h"
      6 
      7 #include "base/files/file_util.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/strings/string_util.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/values.h"
     14 #include "chrome/common/chrome_constants.h"
     15 #include "chrome/common/url_constants.h"
     16 #include "chrome/grit/generated_resources.h"
     17 #include "extensions/common/error_utils.h"
     18 #include "extensions/common/extension_urls.h"
     19 #include "extensions/common/file_util.h"
     20 #include "extensions/common/manifest.h"
     21 #include "extensions/common/manifest_constants.h"
     22 #include "extensions/common/manifest_handlers/permissions_parser.h"
     23 #include "extensions/common/manifest_handlers/shared_module_info.h"
     24 #include "extensions/common/permissions/api_permission.h"
     25 #include "extensions/common/permissions/api_permission_set.h"
     26 #include "ui/base/l10n/l10n_util.h"
     27 
     28 #if defined(USE_AURA)
     29 #include "ui/keyboard/keyboard_constants.h"
     30 #endif
     31 
     32 namespace extensions {
     33 
     34 namespace keys = manifest_keys;
     35 namespace errors = manifest_errors;
     36 
     37 namespace {
     38 
     39 const char kOverrideExtentUrlPatternFormat[] = "chrome://%s/*";
     40 
     41 const GURL& GetManifestURL(const Extension* extension,
     42                            const std::string& key) {
     43   ManifestURL* manifest_url =
     44       static_cast<ManifestURL*>(extension->GetManifestData(key));
     45   return manifest_url ? manifest_url->url_ : GURL::EmptyGURL();
     46 }
     47 
     48 }  // namespace
     49 
     50 // static
     51 const GURL& ManifestURL::GetDevToolsPage(const Extension* extension) {
     52   return GetManifestURL(extension, keys::kDevToolsPage);
     53 }
     54 
     55 // static
     56 const GURL ManifestURL::GetHomepageURL(const Extension* extension) {
     57   const GURL& homepage_url = GetManifestURL(extension, keys::kHomepageURL);
     58   if (homepage_url.is_valid())
     59     return homepage_url;
     60   bool use_webstore_url = UpdatesFromGallery(extension) &&
     61                           !SharedModuleInfo::IsSharedModule(extension);
     62   return use_webstore_url
     63              ? GURL(extension_urls::GetWebstoreItemDetailURLPrefix() +
     64                     extension->id())
     65              : GURL::EmptyGURL();
     66 }
     67 
     68 // static
     69 bool ManifestURL::SpecifiedHomepageURL(const Extension* extension) {
     70   return GetManifestURL(extension, keys::kHomepageURL).is_valid();
     71 }
     72 
     73 // static
     74 const GURL& ManifestURL::GetUpdateURL(const Extension* extension) {
     75   return GetManifestURL(extension, keys::kUpdateURL);
     76 }
     77 
     78 // static
     79 bool ManifestURL::UpdatesFromGallery(const Extension* extension) {
     80   return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension));
     81 }
     82 
     83 // static
     84 bool  ManifestURL::UpdatesFromGallery(const base::DictionaryValue* manifest) {
     85   std::string url;
     86   if (!manifest->GetString(keys::kUpdateURL, &url))
     87     return false;
     88   return extension_urls::IsWebstoreUpdateUrl(GURL(url));
     89 }
     90 
     91 // static
     92 const GURL& ManifestURL::GetAboutPage(const Extension* extension) {
     93   return GetManifestURL(extension, keys::kAboutPage);
     94 }
     95 
     96 // static
     97 const GURL ManifestURL::GetDetailsURL(const Extension* extension) {
     98   return extension->from_webstore() ?
     99       GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
    100       GURL::EmptyGURL();
    101 }
    102 
    103 URLOverrides::URLOverrides() {
    104 }
    105 
    106 URLOverrides::~URLOverrides() {
    107 }
    108 
    109 static base::LazyInstance<URLOverrides::URLOverrideMap> g_empty_url_overrides =
    110     LAZY_INSTANCE_INITIALIZER;
    111 
    112 // static
    113 const URLOverrides::URLOverrideMap&
    114     URLOverrides::GetChromeURLOverrides(const Extension* extension) {
    115   URLOverrides* url_overrides = static_cast<URLOverrides*>(
    116       extension->GetManifestData(keys::kChromeURLOverrides));
    117   return url_overrides ?
    118          url_overrides->chrome_url_overrides_ :
    119          g_empty_url_overrides.Get();
    120 }
    121 
    122 DevToolsPageHandler::DevToolsPageHandler() {
    123 }
    124 
    125 DevToolsPageHandler::~DevToolsPageHandler() {
    126 }
    127 
    128 bool DevToolsPageHandler::Parse(Extension* extension, base::string16* error) {
    129   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
    130   std::string devtools_str;
    131   if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
    132     *error = base::ASCIIToUTF16(errors::kInvalidDevToolsPage);
    133     return false;
    134   }
    135   manifest_url->url_ = extension->GetResourceURL(devtools_str);
    136   extension->SetManifestData(keys::kDevToolsPage, manifest_url.release());
    137   PermissionsParser::AddAPIPermission(extension, APIPermission::kDevtools);
    138   return true;
    139 }
    140 
    141 const std::vector<std::string> DevToolsPageHandler::Keys() const {
    142   return SingleKey(keys::kDevToolsPage);
    143 }
    144 
    145 HomepageURLHandler::HomepageURLHandler() {
    146 }
    147 
    148 HomepageURLHandler::~HomepageURLHandler() {
    149 }
    150 
    151 bool HomepageURLHandler::Parse(Extension* extension, base::string16* error) {
    152   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
    153   std::string homepage_url_str;
    154   if (!extension->manifest()->GetString(keys::kHomepageURL,
    155                                         &homepage_url_str)) {
    156     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidHomepageURL,
    157                                                  std::string());
    158     return false;
    159   }
    160   manifest_url->url_ = GURL(homepage_url_str);
    161   if (!manifest_url->url_.is_valid() ||
    162       !manifest_url->url_.SchemeIsHTTPOrHTTPS()) {
    163     *error = ErrorUtils::FormatErrorMessageUTF16(
    164         errors::kInvalidHomepageURL, homepage_url_str);
    165     return false;
    166   }
    167   extension->SetManifestData(keys::kHomepageURL, manifest_url.release());
    168   return true;
    169 }
    170 
    171 const std::vector<std::string> HomepageURLHandler::Keys() const {
    172   return SingleKey(keys::kHomepageURL);
    173 }
    174 
    175 UpdateURLHandler::UpdateURLHandler() {
    176 }
    177 
    178 UpdateURLHandler::~UpdateURLHandler() {
    179 }
    180 
    181 bool UpdateURLHandler::Parse(Extension* extension, base::string16* error) {
    182   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
    183   std::string tmp_update_url;
    184 
    185   if (!extension->manifest()->GetString(keys::kUpdateURL, &tmp_update_url)) {
    186     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL,
    187                                                  std::string());
    188     return false;
    189   }
    190 
    191   manifest_url->url_ = GURL(tmp_update_url);
    192   if (!manifest_url->url_.is_valid() ||
    193       manifest_url->url_.has_ref()) {
    194     *error = ErrorUtils::FormatErrorMessageUTF16(
    195         errors::kInvalidUpdateURL, tmp_update_url);
    196     return false;
    197   }
    198 
    199   extension->SetManifestData(keys::kUpdateURL, manifest_url.release());
    200   return true;
    201 }
    202 
    203 const std::vector<std::string> UpdateURLHandler::Keys() const {
    204   return SingleKey(keys::kUpdateURL);
    205 }
    206 
    207 AboutPageHandler::AboutPageHandler() {
    208 }
    209 
    210 AboutPageHandler::~AboutPageHandler() {
    211 }
    212 
    213 bool AboutPageHandler::Parse(Extension* extension, base::string16* error) {
    214   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
    215   std::string about_str;
    216   if (!extension->manifest()->GetString(keys::kAboutPage, &about_str)) {
    217     *error = base::ASCIIToUTF16(errors::kInvalidAboutPage);
    218     return false;
    219   }
    220 
    221   GURL absolute(about_str);
    222   if (absolute.is_valid()) {
    223     *error = base::ASCIIToUTF16(errors::kInvalidAboutPageExpectRelativePath);
    224     return false;
    225   }
    226   manifest_url->url_ = extension->GetResourceURL(about_str);
    227   if (!manifest_url->url_.is_valid()) {
    228     *error = base::ASCIIToUTF16(errors::kInvalidAboutPage);
    229     return false;
    230   }
    231   extension->SetManifestData(keys::kAboutPage, manifest_url.release());
    232   return true;
    233 }
    234 
    235 bool AboutPageHandler::Validate(const Extension* extension,
    236                                 std::string* error,
    237                                 std::vector<InstallWarning>* warnings) const {
    238   // Validate path to the options page.
    239   if (!extensions::ManifestURL::GetAboutPage(extension).is_empty()) {
    240     const base::FilePath about_path =
    241         extensions::file_util::ExtensionURLToRelativeFilePath(
    242             extensions::ManifestURL::GetAboutPage(extension));
    243     const base::FilePath path =
    244         extension->GetResource(about_path).GetFilePath();
    245     if (path.empty() || !base::PathExists(path)) {
    246       *error = l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_ABOUT_PAGE_FAILED,
    247                                          about_path.LossyDisplayName());
    248       return false;
    249     }
    250   }
    251   return true;
    252 }
    253 
    254 const std::vector<std::string> AboutPageHandler::Keys() const {
    255   return SingleKey(keys::kAboutPage);
    256 }
    257 
    258 URLOverridesHandler::URLOverridesHandler() {
    259 }
    260 
    261 URLOverridesHandler::~URLOverridesHandler() {
    262 }
    263 
    264 bool URLOverridesHandler::Parse(Extension* extension, base::string16* error) {
    265   const base::DictionaryValue* overrides = NULL;
    266   if (!extension->manifest()->GetDictionary(keys::kChromeURLOverrides,
    267                                             &overrides)) {
    268     *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
    269     return false;
    270   }
    271   scoped_ptr<URLOverrides> url_overrides(new URLOverrides);
    272   // Validate that the overrides are all strings
    273   for (base::DictionaryValue::Iterator iter(*overrides); !iter.IsAtEnd();
    274          iter.Advance()) {
    275     std::string page = iter.key();
    276     std::string val;
    277     // Restrict override pages to a list of supported URLs.
    278     bool is_override = (page != chrome::kChromeUINewTabHost &&
    279                         page != chrome::kChromeUIBookmarksHost &&
    280                         page != chrome::kChromeUIHistoryHost);
    281 #if defined(OS_CHROMEOS)
    282     is_override = (is_override &&
    283                    page != chrome::kChromeUIActivationMessageHost);
    284 #endif
    285 #if defined(OS_CHROMEOS)
    286     is_override = (is_override && page != keyboard::kKeyboardHost);
    287 #endif
    288 
    289     if (is_override || !iter.value().GetAsString(&val)) {
    290       *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
    291       return false;
    292     }
    293     // Replace the entry with a fully qualified chrome-extension:// URL.
    294     url_overrides->chrome_url_overrides_[page] = extension->GetResourceURL(val);
    295 
    296     // For component extensions, add override URL to extent patterns.
    297     if (extension->is_legacy_packaged_app() &&
    298         extension->location() == Manifest::COMPONENT) {
    299       URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
    300       std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
    301                                            page.c_str());
    302       if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
    303         *error = ErrorUtils::FormatErrorMessageUTF16(
    304             errors::kInvalidURLPatternError, url);
    305         return false;
    306       }
    307       extension->AddWebExtentPattern(pattern);
    308     }
    309   }
    310 
    311   // An extension may override at most one page.
    312   if (overrides->size() > 1) {
    313     *error = base::ASCIIToUTF16(errors::kMultipleOverrides);
    314     return false;
    315   }
    316   extension->SetManifestData(keys::kChromeURLOverrides,
    317                              url_overrides.release());
    318   return true;
    319 }
    320 
    321 const std::vector<std::string> URLOverridesHandler::Keys() const {
    322   return SingleKey(keys::kChromeURLOverrides);
    323 }
    324 
    325 }  // namespace extensions
    326