• 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/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