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 32namespace extensions { 33 34namespace keys = manifest_keys; 35namespace errors = manifest_errors; 36 37namespace { 38 39const char kOverrideExtentUrlPatternFormat[] = "chrome://%s/*"; 40 41const 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 51const GURL& ManifestURL::GetDevToolsPage(const Extension* extension) { 52 return GetManifestURL(extension, keys::kDevToolsPage); 53} 54 55// static 56const 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 69bool ManifestURL::SpecifiedHomepageURL(const Extension* extension) { 70 return GetManifestURL(extension, keys::kHomepageURL).is_valid(); 71} 72 73// static 74const GURL& ManifestURL::GetUpdateURL(const Extension* extension) { 75 return GetManifestURL(extension, keys::kUpdateURL); 76} 77 78// static 79bool ManifestURL::UpdatesFromGallery(const Extension* extension) { 80 return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension)); 81} 82 83// static 84bool 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 92const GURL& ManifestURL::GetAboutPage(const Extension* extension) { 93 return GetManifestURL(extension, keys::kAboutPage); 94} 95 96// static 97const GURL ManifestURL::GetDetailsURL(const Extension* extension) { 98 return extension->from_webstore() ? 99 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) : 100 GURL::EmptyGURL(); 101} 102 103URLOverrides::URLOverrides() { 104} 105 106URLOverrides::~URLOverrides() { 107} 108 109static base::LazyInstance<URLOverrides::URLOverrideMap> g_empty_url_overrides = 110 LAZY_INSTANCE_INITIALIZER; 111 112// static 113const 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 122DevToolsPageHandler::DevToolsPageHandler() { 123} 124 125DevToolsPageHandler::~DevToolsPageHandler() { 126} 127 128bool 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 141const std::vector<std::string> DevToolsPageHandler::Keys() const { 142 return SingleKey(keys::kDevToolsPage); 143} 144 145HomepageURLHandler::HomepageURLHandler() { 146} 147 148HomepageURLHandler::~HomepageURLHandler() { 149} 150 151bool 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 171const std::vector<std::string> HomepageURLHandler::Keys() const { 172 return SingleKey(keys::kHomepageURL); 173} 174 175UpdateURLHandler::UpdateURLHandler() { 176} 177 178UpdateURLHandler::~UpdateURLHandler() { 179} 180 181bool 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 203const std::vector<std::string> UpdateURLHandler::Keys() const { 204 return SingleKey(keys::kUpdateURL); 205} 206 207AboutPageHandler::AboutPageHandler() { 208} 209 210AboutPageHandler::~AboutPageHandler() { 211} 212 213bool 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 235bool 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 254const std::vector<std::string> AboutPageHandler::Keys() const { 255 return SingleKey(keys::kAboutPage); 256} 257 258URLOverridesHandler::URLOverridesHandler() { 259} 260 261URLOverridesHandler::~URLOverridesHandler() { 262} 263 264bool 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 321const std::vector<std::string> URLOverridesHandler::Keys() const { 322 return SingleKey(keys::kChromeURLOverrides); 323} 324 325} // namespace extensions 326