• 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/permissions/api_permission.h"
22 #include "extensions/common/permissions/api_permission_set.h"
23 #include "extensions/common/permissions/permissions_data.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
GetDetailsURL(const Extension * extension)88 const GURL ManifestURL::GetDetailsURL(const Extension* extension) {
89   return extension->from_webstore() ?
90       GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
91       GURL::EmptyGURL();
92 }
93 
URLOverrides()94 URLOverrides::URLOverrides() {
95 }
96 
~URLOverrides()97 URLOverrides::~URLOverrides() {
98 }
99 
100 static base::LazyInstance<URLOverrides::URLOverrideMap> g_empty_url_overrides =
101     LAZY_INSTANCE_INITIALIZER;
102 
103 // static
104 const URLOverrides::URLOverrideMap&
GetChromeURLOverrides(const Extension * extension)105     URLOverrides::GetChromeURLOverrides(const Extension* extension) {
106   URLOverrides* url_overrides = static_cast<URLOverrides*>(
107       extension->GetManifestData(keys::kChromeURLOverrides));
108   return url_overrides ?
109          url_overrides->chrome_url_overrides_ :
110          g_empty_url_overrides.Get();
111 }
112 
DevToolsPageHandler()113 DevToolsPageHandler::DevToolsPageHandler() {
114 }
115 
~DevToolsPageHandler()116 DevToolsPageHandler::~DevToolsPageHandler() {
117 }
118 
Parse(Extension * extension,base::string16 * error)119 bool DevToolsPageHandler::Parse(Extension* extension, base::string16* error) {
120   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
121   std::string devtools_str;
122   if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
123     *error = ASCIIToUTF16(errors::kInvalidDevToolsPage);
124     return false;
125   }
126   manifest_url->url_ = extension->GetResourceURL(devtools_str);
127   extension->SetManifestData(keys::kDevToolsPage, manifest_url.release());
128   PermissionsData::GetInitialAPIPermissions(extension)->insert(
129       APIPermission::kDevtools);
130   return true;
131 }
132 
Keys() const133 const std::vector<std::string> DevToolsPageHandler::Keys() const {
134   return SingleKey(keys::kDevToolsPage);
135 }
136 
HomepageURLHandler()137 HomepageURLHandler::HomepageURLHandler() {
138 }
139 
~HomepageURLHandler()140 HomepageURLHandler::~HomepageURLHandler() {
141 }
142 
Parse(Extension * extension,base::string16 * error)143 bool HomepageURLHandler::Parse(Extension* extension, base::string16* error) {
144   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
145   std::string homepage_url_str;
146   if (!extension->manifest()->GetString(keys::kHomepageURL,
147                                         &homepage_url_str)) {
148     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidHomepageURL,
149                                                  std::string());
150     return false;
151   }
152   manifest_url->url_ = GURL(homepage_url_str);
153   if (!manifest_url->url_.is_valid() ||
154       !manifest_url->url_.SchemeIsHTTPOrHTTPS()) {
155     *error = ErrorUtils::FormatErrorMessageUTF16(
156         errors::kInvalidHomepageURL, homepage_url_str);
157     return false;
158   }
159   extension->SetManifestData(keys::kHomepageURL, manifest_url.release());
160   return true;
161 }
162 
Keys() const163 const std::vector<std::string> HomepageURLHandler::Keys() const {
164   return SingleKey(keys::kHomepageURL);
165 }
166 
UpdateURLHandler()167 UpdateURLHandler::UpdateURLHandler() {
168 }
169 
~UpdateURLHandler()170 UpdateURLHandler::~UpdateURLHandler() {
171 }
172 
Parse(Extension * extension,base::string16 * error)173 bool UpdateURLHandler::Parse(Extension* extension, base::string16* error) {
174   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
175   std::string tmp_update_url;
176 
177   if (!extension->manifest()->GetString(keys::kUpdateURL, &tmp_update_url)) {
178     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL,
179                                                  std::string());
180     return false;
181   }
182 
183   manifest_url->url_ = GURL(tmp_update_url);
184   if (!manifest_url->url_.is_valid() ||
185       manifest_url->url_.has_ref()) {
186     *error = ErrorUtils::FormatErrorMessageUTF16(
187         errors::kInvalidUpdateURL, tmp_update_url);
188     return false;
189   }
190 
191   extension->SetManifestData(keys::kUpdateURL, manifest_url.release());
192   return true;
193 }
194 
Keys() const195 const std::vector<std::string> UpdateURLHandler::Keys() const {
196   return SingleKey(keys::kUpdateURL);
197 }
198 
OptionsPageHandler()199 OptionsPageHandler::OptionsPageHandler() {
200 }
201 
~OptionsPageHandler()202 OptionsPageHandler::~OptionsPageHandler() {
203 }
204 
Parse(Extension * extension,base::string16 * error)205 bool OptionsPageHandler::Parse(Extension* extension, base::string16* error) {
206   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
207   std::string options_str;
208   if (!extension->manifest()->GetString(keys::kOptionsPage, &options_str)) {
209     *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
210     return false;
211   }
212 
213   if (extension->is_hosted_app()) {
214     // hosted apps require an absolute URL.
215     GURL options_url(options_str);
216     if (!options_url.is_valid() ||
217         !options_url.SchemeIsHTTPOrHTTPS()) {
218       *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
219       return false;
220     }
221     manifest_url->url_ = options_url;
222   } else {
223     GURL absolute(options_str);
224     if (absolute.is_valid()) {
225       *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
226       return false;
227     }
228     manifest_url->url_ = extension->GetResourceURL(options_str);
229     if (!manifest_url->url_.is_valid()) {
230       *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
231       return false;
232     }
233   }
234 
235   extension->SetManifestData(keys::kOptionsPage, manifest_url.release());
236   return true;
237 }
238 
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const239 bool OptionsPageHandler::Validate(const Extension* extension,
240                                   std::string* error,
241                                   std::vector<InstallWarning>* warnings) const {
242   // Validate path to the options page.  Don't check the URL for hosted apps,
243   // because they are expected to refer to an external URL.
244   if (!extensions::ManifestURL::GetOptionsPage(extension).is_empty() &&
245       !extension->is_hosted_app()) {
246     const base::FilePath options_path =
247         extensions::file_util::ExtensionURLToRelativeFilePath(
248             extensions::ManifestURL::GetOptionsPage(extension));
249     const base::FilePath path =
250         extension->GetResource(options_path).GetFilePath();
251     if (path.empty() || !base::PathExists(path)) {
252       *error =
253           l10n_util::GetStringFUTF8(
254               IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED,
255               options_path.LossyDisplayName());
256       return false;
257     }
258   }
259   return true;
260 }
261 
Keys() const262 const std::vector<std::string> OptionsPageHandler::Keys() const {
263   return SingleKey(keys::kOptionsPage);
264 }
265 
URLOverridesHandler()266 URLOverridesHandler::URLOverridesHandler() {
267 }
268 
~URLOverridesHandler()269 URLOverridesHandler::~URLOverridesHandler() {
270 }
271 
Parse(Extension * extension,base::string16 * error)272 bool URLOverridesHandler::Parse(Extension* extension, base::string16* error) {
273   const base::DictionaryValue* overrides = NULL;
274   if (!extension->manifest()->GetDictionary(keys::kChromeURLOverrides,
275                                             &overrides)) {
276     *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
277     return false;
278   }
279   scoped_ptr<URLOverrides> url_overrides(new URLOverrides);
280   // Validate that the overrides are all strings
281   for (base::DictionaryValue::Iterator iter(*overrides); !iter.IsAtEnd();
282          iter.Advance()) {
283     std::string page = iter.key();
284     std::string val;
285     // Restrict override pages to a list of supported URLs.
286     bool is_override = (page != chrome::kChromeUINewTabHost &&
287                         page != chrome::kChromeUIBookmarksHost &&
288                         page != chrome::kChromeUIHistoryHost);
289 #if defined(OS_CHROMEOS)
290     is_override = (is_override &&
291                    page != chrome::kChromeUIActivationMessageHost);
292 #endif
293 #if defined(OS_CHROMEOS)
294     is_override = (is_override && page != keyboard::kKeyboardWebUIHost);
295 #endif
296 #if defined(ENABLE_ENHANCED_BOOKMARKS)
297     is_override = (is_override &&
298                    !(extension->location() == Manifest::COMPONENT &&
299                      page ==  chrome::kChromeUIEnhancedBookmarksHost));
300 #endif
301 
302     if (is_override || !iter.value().GetAsString(&val)) {
303       *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
304       return false;
305     }
306     // Replace the entry with a fully qualified chrome-extension:// URL.
307     url_overrides->chrome_url_overrides_[page] = extension->GetResourceURL(val);
308 
309     // For component extensions, add override URL to extent patterns.
310     if (extension->is_legacy_packaged_app() &&
311         extension->location() == Manifest::COMPONENT) {
312       URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
313       std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
314                                            page.c_str());
315       if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
316         *error = ErrorUtils::FormatErrorMessageUTF16(
317             errors::kInvalidURLPatternError, url);
318         return false;
319       }
320       extension->AddWebExtentPattern(pattern);
321     }
322   }
323 
324   // An extension may override at most one page.
325   if (overrides->size() > 1) {
326     *error = ASCIIToUTF16(errors::kMultipleOverrides);
327     return false;
328   }
329   extension->SetManifestData(keys::kChromeURLOverrides,
330                              url_overrides.release());
331   return true;
332 }
333 
Keys() const334 const std::vector<std::string> URLOverridesHandler::Keys() const {
335   return SingleKey(keys::kChromeURLOverrides);
336 }
337 
338 }  // namespace extensions
339