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