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.
5 #include "chrome/common/extensions/manifest_url_handler.h"
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"
29 #include "ui/keyboard/keyboard_constants.h"
32 namespace extensions
{
34 namespace keys
= manifest_keys
;
35 namespace errors
= manifest_errors
;
39 const char kOverrideExtentUrlPatternFormat
[] = "chrome://%s/*";
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();
51 const GURL
& ManifestURL::GetDevToolsPage(const Extension
* extension
) {
52 return GetManifestURL(extension
, keys::kDevToolsPage
);
56 const GURL
ManifestURL::GetHomepageURL(const Extension
* extension
) {
57 const GURL
& homepage_url
= GetManifestURL(extension
, keys::kHomepageURL
);
58 if (homepage_url
.is_valid())
60 bool use_webstore_url
= UpdatesFromGallery(extension
) &&
61 !SharedModuleInfo::IsSharedModule(extension
);
62 return use_webstore_url
63 ? GURL(extension_urls::GetWebstoreItemDetailURLPrefix() +
69 bool ManifestURL::SpecifiedHomepageURL(const Extension
* extension
) {
70 return GetManifestURL(extension
, keys::kHomepageURL
).is_valid();
74 const GURL
& ManifestURL::GetUpdateURL(const Extension
* extension
) {
75 return GetManifestURL(extension
, keys::kUpdateURL
);
79 bool ManifestURL::UpdatesFromGallery(const Extension
* extension
) {
80 return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension
));
84 bool ManifestURL::UpdatesFromGallery(const base::DictionaryValue
* manifest
) {
86 if (!manifest
->GetString(keys::kUpdateURL
, &url
))
88 return extension_urls::IsWebstoreUpdateUrl(GURL(url
));
92 const GURL
& ManifestURL::GetAboutPage(const Extension
* extension
) {
93 return GetManifestURL(extension
, keys::kAboutPage
);
97 const GURL
ManifestURL::GetDetailsURL(const Extension
* extension
) {
98 return extension
->from_webstore() ?
99 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension
->id()) :
103 URLOverrides::URLOverrides() {
106 URLOverrides::~URLOverrides() {
109 static base::LazyInstance
<URLOverrides::URLOverrideMap
> g_empty_url_overrides
=
110 LAZY_INSTANCE_INITIALIZER
;
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();
122 DevToolsPageHandler::DevToolsPageHandler() {
125 DevToolsPageHandler::~DevToolsPageHandler() {
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
);
135 manifest_url
->url_
= extension
->GetResourceURL(devtools_str
);
136 extension
->SetManifestData(keys::kDevToolsPage
, manifest_url
.release());
137 PermissionsParser::AddAPIPermission(extension
, APIPermission::kDevtools
);
141 const std::vector
<std::string
> DevToolsPageHandler::Keys() const {
142 return SingleKey(keys::kDevToolsPage
);
145 HomepageURLHandler::HomepageURLHandler() {
148 HomepageURLHandler::~HomepageURLHandler() {
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
,
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
);
167 extension
->SetManifestData(keys::kHomepageURL
, manifest_url
.release());
171 const std::vector
<std::string
> HomepageURLHandler::Keys() const {
172 return SingleKey(keys::kHomepageURL
);
175 UpdateURLHandler::UpdateURLHandler() {
178 UpdateURLHandler::~UpdateURLHandler() {
181 bool UpdateURLHandler::Parse(Extension
* extension
, base::string16
* error
) {
182 scoped_ptr
<ManifestURL
> manifest_url(new ManifestURL
);
183 std::string tmp_update_url
;
185 if (!extension
->manifest()->GetString(keys::kUpdateURL
, &tmp_update_url
)) {
186 *error
= ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL
,
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
);
199 extension
->SetManifestData(keys::kUpdateURL
, manifest_url
.release());
203 const std::vector
<std::string
> UpdateURLHandler::Keys() const {
204 return SingleKey(keys::kUpdateURL
);
207 AboutPageHandler::AboutPageHandler() {
210 AboutPageHandler::~AboutPageHandler() {
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
);
221 GURL
absolute(about_str
);
222 if (absolute
.is_valid()) {
223 *error
= base::ASCIIToUTF16(errors::kInvalidAboutPageExpectRelativePath
);
226 manifest_url
->url_
= extension
->GetResourceURL(about_str
);
227 if (!manifest_url
->url_
.is_valid()) {
228 *error
= base::ASCIIToUTF16(errors::kInvalidAboutPage
);
231 extension
->SetManifestData(keys::kAboutPage
, manifest_url
.release());
235 bool AboutPageHandler::Validate(const Extension
* extension
,
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());
254 const std::vector
<std::string
> AboutPageHandler::Keys() const {
255 return SingleKey(keys::kAboutPage
);
258 URLOverridesHandler::URLOverridesHandler() {
261 URLOverridesHandler::~URLOverridesHandler() {
264 bool URLOverridesHandler::Parse(Extension
* extension
, base::string16
* error
) {
265 const base::DictionaryValue
* overrides
= NULL
;
266 if (!extension
->manifest()->GetDictionary(keys::kChromeURLOverrides
,
268 *error
= base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides
);
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();
275 std::string page
= iter
.key();
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
);
285 #if defined(OS_CHROMEOS)
286 is_override
= (is_override
&& page
!= keyboard::kKeyboardHost
);
289 if (is_override
|| !iter
.value().GetAsString(&val
)) {
290 *error
= base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides
);
293 // Replace the entry with a fully qualified chrome-extension:// URL.
294 url_overrides
->chrome_url_overrides_
[page
] = extension
->GetResourceURL(val
);
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
,
302 if (pattern
.Parse(url
) != URLPattern::PARSE_SUCCESS
) {
303 *error
= ErrorUtils::FormatErrorMessageUTF16(
304 errors::kInvalidURLPatternError
, url
);
307 extension
->AddWebExtentPattern(pattern
);
311 // An extension may override at most one page.
312 if (overrides
->size() > 1) {
313 *error
= base::ASCIIToUTF16(errors::kMultipleOverrides
);
316 extension
->SetManifestData(keys::kChromeURLOverrides
,
317 url_overrides
.release());
321 const std::vector
<std::string
> URLOverridesHandler::Keys() const {
322 return SingleKey(keys::kChromeURLOverrides
);
325 } // namespace extensions