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