• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/manifest_handlers/permissions_parser.h"
22 #include "extensions/common/permissions/api_permission.h"
23 #include "extensions/common/permissions/api_permission_set.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 
GetManifestURL(const Extension * extension,const std::string & key)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
GetDevToolsPage(const Extension * extension)50 const GURL& ManifestURL::GetDevToolsPage(const Extension* extension) {
51   return GetManifestURL(extension, keys::kDevToolsPage);
52 }
53 
54 // static
GetHomepageURL(const Extension * extension)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
GetUpdateURL(const Extension * extension)65 const GURL& ManifestURL::GetUpdateURL(const Extension* extension) {
66   return GetManifestURL(extension, keys::kUpdateURL);
67 }
68 
69 // static
UpdatesFromGallery(const Extension * extension)70 bool ManifestURL::UpdatesFromGallery(const Extension* extension) {
71   return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension));
72 }
73 
74 // static
UpdatesFromGallery(const base::DictionaryValue * manifest)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
GetOptionsPage(const Extension * extension)83 const GURL& ManifestURL::GetOptionsPage(const Extension* extension) {
84   return GetManifestURL(extension, keys::kOptionsPage);
85 }
86 
87 // static
GetAboutPage(const Extension * extension)88 const GURL& ManifestURL::GetAboutPage(const Extension* extension) {
89   return GetManifestURL(extension, keys::kAboutPage);
90 }
91 
92 // static
GetDetailsURL(const Extension * extension)93 const GURL ManifestURL::GetDetailsURL(const Extension* extension) {
94   return extension->from_webstore() ?
95       GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
96       GURL::EmptyGURL();
97 }
98 
URLOverrides()99 URLOverrides::URLOverrides() {
100 }
101 
~URLOverrides()102 URLOverrides::~URLOverrides() {
103 }
104 
105 static base::LazyInstance<URLOverrides::URLOverrideMap> g_empty_url_overrides =
106     LAZY_INSTANCE_INITIALIZER;
107 
108 // static
109 const URLOverrides::URLOverrideMap&
GetChromeURLOverrides(const Extension * extension)110     URLOverrides::GetChromeURLOverrides(const Extension* extension) {
111   URLOverrides* url_overrides = static_cast<URLOverrides*>(
112       extension->GetManifestData(keys::kChromeURLOverrides));
113   return url_overrides ?
114          url_overrides->chrome_url_overrides_ :
115          g_empty_url_overrides.Get();
116 }
117 
DevToolsPageHandler()118 DevToolsPageHandler::DevToolsPageHandler() {
119 }
120 
~DevToolsPageHandler()121 DevToolsPageHandler::~DevToolsPageHandler() {
122 }
123 
Parse(Extension * extension,base::string16 * error)124 bool DevToolsPageHandler::Parse(Extension* extension, base::string16* error) {
125   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
126   std::string devtools_str;
127   if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
128     *error = base::ASCIIToUTF16(errors::kInvalidDevToolsPage);
129     return false;
130   }
131   manifest_url->url_ = extension->GetResourceURL(devtools_str);
132   extension->SetManifestData(keys::kDevToolsPage, manifest_url.release());
133   PermissionsParser::AddAPIPermission(extension, APIPermission::kDevtools);
134   return true;
135 }
136 
Keys() const137 const std::vector<std::string> DevToolsPageHandler::Keys() const {
138   return SingleKey(keys::kDevToolsPage);
139 }
140 
HomepageURLHandler()141 HomepageURLHandler::HomepageURLHandler() {
142 }
143 
~HomepageURLHandler()144 HomepageURLHandler::~HomepageURLHandler() {
145 }
146 
Parse(Extension * extension,base::string16 * error)147 bool HomepageURLHandler::Parse(Extension* extension, base::string16* error) {
148   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
149   std::string homepage_url_str;
150   if (!extension->manifest()->GetString(keys::kHomepageURL,
151                                         &homepage_url_str)) {
152     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidHomepageURL,
153                                                  std::string());
154     return false;
155   }
156   manifest_url->url_ = GURL(homepage_url_str);
157   if (!manifest_url->url_.is_valid() ||
158       !manifest_url->url_.SchemeIsHTTPOrHTTPS()) {
159     *error = ErrorUtils::FormatErrorMessageUTF16(
160         errors::kInvalidHomepageURL, homepage_url_str);
161     return false;
162   }
163   extension->SetManifestData(keys::kHomepageURL, manifest_url.release());
164   return true;
165 }
166 
Keys() const167 const std::vector<std::string> HomepageURLHandler::Keys() const {
168   return SingleKey(keys::kHomepageURL);
169 }
170 
UpdateURLHandler()171 UpdateURLHandler::UpdateURLHandler() {
172 }
173 
~UpdateURLHandler()174 UpdateURLHandler::~UpdateURLHandler() {
175 }
176 
Parse(Extension * extension,base::string16 * error)177 bool UpdateURLHandler::Parse(Extension* extension, base::string16* error) {
178   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
179   std::string tmp_update_url;
180 
181   if (!extension->manifest()->GetString(keys::kUpdateURL, &tmp_update_url)) {
182     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL,
183                                                  std::string());
184     return false;
185   }
186 
187   manifest_url->url_ = GURL(tmp_update_url);
188   if (!manifest_url->url_.is_valid() ||
189       manifest_url->url_.has_ref()) {
190     *error = ErrorUtils::FormatErrorMessageUTF16(
191         errors::kInvalidUpdateURL, tmp_update_url);
192     return false;
193   }
194 
195   extension->SetManifestData(keys::kUpdateURL, manifest_url.release());
196   return true;
197 }
198 
Keys() const199 const std::vector<std::string> UpdateURLHandler::Keys() const {
200   return SingleKey(keys::kUpdateURL);
201 }
202 
OptionsPageHandler()203 OptionsPageHandler::OptionsPageHandler() {
204 }
205 
~OptionsPageHandler()206 OptionsPageHandler::~OptionsPageHandler() {
207 }
208 
Parse(Extension * extension,base::string16 * error)209 bool OptionsPageHandler::Parse(Extension* extension, base::string16* error) {
210   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
211   std::string options_str;
212   if (!extension->manifest()->GetString(keys::kOptionsPage, &options_str)) {
213     *error = base::ASCIIToUTF16(errors::kInvalidOptionsPage);
214     return false;
215   }
216 
217   if (extension->is_hosted_app()) {
218     // hosted apps require an absolute URL.
219     GURL options_url(options_str);
220     if (!options_url.is_valid() ||
221         !options_url.SchemeIsHTTPOrHTTPS()) {
222       *error = base::ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
223       return false;
224     }
225     manifest_url->url_ = options_url;
226   } else {
227     GURL absolute(options_str);
228     if (absolute.is_valid()) {
229       *error =
230           base::ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
231       return false;
232     }
233     manifest_url->url_ = extension->GetResourceURL(options_str);
234     if (!manifest_url->url_.is_valid()) {
235       *error = base::ASCIIToUTF16(errors::kInvalidOptionsPage);
236       return false;
237     }
238   }
239 
240   extension->SetManifestData(keys::kOptionsPage, manifest_url.release());
241   return true;
242 }
243 
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const244 bool OptionsPageHandler::Validate(const Extension* extension,
245                                   std::string* error,
246                                   std::vector<InstallWarning>* warnings) const {
247   // Validate path to the options page.  Don't check the URL for hosted apps,
248   // because they are expected to refer to an external URL.
249   if (!extensions::ManifestURL::GetOptionsPage(extension).is_empty() &&
250       !extension->is_hosted_app()) {
251     const base::FilePath options_path =
252         extensions::file_util::ExtensionURLToRelativeFilePath(
253             extensions::ManifestURL::GetOptionsPage(extension));
254     const base::FilePath path =
255         extension->GetResource(options_path).GetFilePath();
256     if (path.empty() || !base::PathExists(path)) {
257       *error =
258           l10n_util::GetStringFUTF8(
259               IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED,
260               options_path.LossyDisplayName());
261       return false;
262     }
263   }
264   return true;
265 }
266 
Keys() const267 const std::vector<std::string> OptionsPageHandler::Keys() const {
268   return SingleKey(keys::kOptionsPage);
269 }
270 
AboutPageHandler()271 AboutPageHandler::AboutPageHandler() {
272 }
273 
~AboutPageHandler()274 AboutPageHandler::~AboutPageHandler() {
275 }
276 
Parse(Extension * extension,base::string16 * error)277 bool AboutPageHandler::Parse(Extension* extension, base::string16* error) {
278   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
279   std::string about_str;
280   if (!extension->manifest()->GetString(keys::kAboutPage, &about_str)) {
281     *error = base::ASCIIToUTF16(errors::kInvalidAboutPage);
282     return false;
283   }
284 
285   GURL absolute(about_str);
286   if (absolute.is_valid()) {
287     *error = base::ASCIIToUTF16(errors::kInvalidAboutPageExpectRelativePath);
288     return false;
289   }
290   manifest_url->url_ = extension->GetResourceURL(about_str);
291   if (!manifest_url->url_.is_valid()) {
292     *error = base::ASCIIToUTF16(errors::kInvalidAboutPage);
293     return false;
294   }
295   extension->SetManifestData(keys::kAboutPage, manifest_url.release());
296   return true;
297 }
298 
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const299 bool AboutPageHandler::Validate(const Extension* extension,
300                                 std::string* error,
301                                 std::vector<InstallWarning>* warnings) const {
302   // Validate path to the options page.
303   if (!extensions::ManifestURL::GetAboutPage(extension).is_empty()) {
304     const base::FilePath about_path =
305         extensions::file_util::ExtensionURLToRelativeFilePath(
306             extensions::ManifestURL::GetAboutPage(extension));
307     const base::FilePath path =
308         extension->GetResource(about_path).GetFilePath();
309     if (path.empty() || !base::PathExists(path)) {
310       *error = l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_ABOUT_PAGE_FAILED,
311                                          about_path.LossyDisplayName());
312       return false;
313     }
314   }
315   return true;
316 }
317 
Keys() const318 const std::vector<std::string> AboutPageHandler::Keys() const {
319   return SingleKey(keys::kAboutPage);
320 }
321 
URLOverridesHandler()322 URLOverridesHandler::URLOverridesHandler() {
323 }
324 
~URLOverridesHandler()325 URLOverridesHandler::~URLOverridesHandler() {
326 }
327 
Parse(Extension * extension,base::string16 * error)328 bool URLOverridesHandler::Parse(Extension* extension, base::string16* error) {
329   const base::DictionaryValue* overrides = NULL;
330   if (!extension->manifest()->GetDictionary(keys::kChromeURLOverrides,
331                                             &overrides)) {
332     *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
333     return false;
334   }
335   scoped_ptr<URLOverrides> url_overrides(new URLOverrides);
336   // Validate that the overrides are all strings
337   for (base::DictionaryValue::Iterator iter(*overrides); !iter.IsAtEnd();
338          iter.Advance()) {
339     std::string page = iter.key();
340     std::string val;
341     // Restrict override pages to a list of supported URLs.
342     bool is_override = (page != chrome::kChromeUINewTabHost &&
343                         page != chrome::kChromeUIBookmarksHost &&
344                         page != chrome::kChromeUIHistoryHost);
345 #if defined(OS_CHROMEOS)
346     is_override = (is_override &&
347                    page != chrome::kChromeUIActivationMessageHost);
348 #endif
349 #if defined(OS_CHROMEOS)
350     is_override = (is_override && page != keyboard::kKeyboardHost);
351 #endif
352 
353     if (is_override || !iter.value().GetAsString(&val)) {
354       *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
355       return false;
356     }
357     // Replace the entry with a fully qualified chrome-extension:// URL.
358     url_overrides->chrome_url_overrides_[page] = extension->GetResourceURL(val);
359 
360     // For component extensions, add override URL to extent patterns.
361     if (extension->is_legacy_packaged_app() &&
362         extension->location() == Manifest::COMPONENT) {
363       URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
364       std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
365                                            page.c_str());
366       if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
367         *error = ErrorUtils::FormatErrorMessageUTF16(
368             errors::kInvalidURLPatternError, url);
369         return false;
370       }
371       extension->AddWebExtentPattern(pattern);
372     }
373   }
374 
375   // An extension may override at most one page.
376   if (overrides->size() > 1) {
377     *error = base::ASCIIToUTF16(errors::kMultipleOverrides);
378     return false;
379   }
380   extension->SetManifestData(keys::kChromeURLOverrides,
381                              url_overrides.release());
382   return true;
383 }
384 
Keys() const385 const std::vector<std::string> URLOverridesHandler::Keys() const {
386   return SingleKey(keys::kChromeURLOverrides);
387 }
388 
389 }  // namespace extensions
390