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
GetManifestURL(const Extension * extension,const std::string & key)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
GetDevToolsPage(const Extension * extension)51 const GURL& ManifestURL::GetDevToolsPage(const Extension* extension) {
52 return GetManifestURL(extension, keys::kDevToolsPage);
53 }
54
55 // static
GetHomepageURL(const Extension * extension)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
SpecifiedHomepageURL(const Extension * extension)69 bool ManifestURL::SpecifiedHomepageURL(const Extension* extension) {
70 return GetManifestURL(extension, keys::kHomepageURL).is_valid();
71 }
72
73 // static
GetUpdateURL(const Extension * extension)74 const GURL& ManifestURL::GetUpdateURL(const Extension* extension) {
75 return GetManifestURL(extension, keys::kUpdateURL);
76 }
77
78 // static
UpdatesFromGallery(const Extension * extension)79 bool ManifestURL::UpdatesFromGallery(const Extension* extension) {
80 return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension));
81 }
82
83 // static
UpdatesFromGallery(const base::DictionaryValue * manifest)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
GetAboutPage(const Extension * extension)92 const GURL& ManifestURL::GetAboutPage(const Extension* extension) {
93 return GetManifestURL(extension, keys::kAboutPage);
94 }
95
96 // static
GetDetailsURL(const Extension * extension)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
URLOverrides()103 URLOverrides::URLOverrides() {
104 }
105
~URLOverrides()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&
GetChromeURLOverrides(const Extension * extension)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
DevToolsPageHandler()122 DevToolsPageHandler::DevToolsPageHandler() {
123 }
124
~DevToolsPageHandler()125 DevToolsPageHandler::~DevToolsPageHandler() {
126 }
127
Parse(Extension * extension,base::string16 * error)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
Keys() const141 const std::vector<std::string> DevToolsPageHandler::Keys() const {
142 return SingleKey(keys::kDevToolsPage);
143 }
144
HomepageURLHandler()145 HomepageURLHandler::HomepageURLHandler() {
146 }
147
~HomepageURLHandler()148 HomepageURLHandler::~HomepageURLHandler() {
149 }
150
Parse(Extension * extension,base::string16 * error)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
Keys() const171 const std::vector<std::string> HomepageURLHandler::Keys() const {
172 return SingleKey(keys::kHomepageURL);
173 }
174
UpdateURLHandler()175 UpdateURLHandler::UpdateURLHandler() {
176 }
177
~UpdateURLHandler()178 UpdateURLHandler::~UpdateURLHandler() {
179 }
180
Parse(Extension * extension,base::string16 * error)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
Keys() const203 const std::vector<std::string> UpdateURLHandler::Keys() const {
204 return SingleKey(keys::kUpdateURL);
205 }
206
AboutPageHandler()207 AboutPageHandler::AboutPageHandler() {
208 }
209
~AboutPageHandler()210 AboutPageHandler::~AboutPageHandler() {
211 }
212
Parse(Extension * extension,base::string16 * error)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
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const235 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
Keys() const254 const std::vector<std::string> AboutPageHandler::Keys() const {
255 return SingleKey(keys::kAboutPage);
256 }
257
URLOverridesHandler()258 URLOverridesHandler::URLOverridesHandler() {
259 }
260
~URLOverridesHandler()261 URLOverridesHandler::~URLOverridesHandler() {
262 }
263
Parse(Extension * extension,base::string16 * error)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
Keys() const321 const std::vector<std::string> URLOverridesHandler::Keys() const {
322 return SingleKey(keys::kChromeURLOverrides);
323 }
324
325 } // namespace extensions
326