• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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 "extensions/common/extension.h"
6 
7 #include "base/base64.h"
8 #include "base/basictypes.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/i18n/rtl.h"
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "base/version.h"
23 #include "content/public/common/url_constants.h"
24 #include "extensions/common/constants.h"
25 #include "extensions/common/error_utils.h"
26 #include "extensions/common/id_util.h"
27 #include "extensions/common/manifest.h"
28 #include "extensions/common/manifest_constants.h"
29 #include "extensions/common/manifest_handler.h"
30 #include "extensions/common/permissions/api_permission_set.h"
31 #include "extensions/common/permissions/permission_set.h"
32 #include "extensions/common/permissions/permissions_data.h"
33 #include "extensions/common/permissions/permissions_info.h"
34 #include "extensions/common/switches.h"
35 #include "extensions/common/url_pattern_set.h"
36 #include "grit/chromium_strings.h"
37 #include "grit/theme_resources.h"
38 #include "net/base/net_util.h"
39 #include "url/url_util.h"
40 
41 #if defined(OS_WIN)
42 #include "grit/generated_resources.h"
43 #endif
44 
45 namespace extensions {
46 
47 namespace keys = manifest_keys;
48 namespace values = manifest_values;
49 namespace errors = manifest_errors;
50 
51 namespace {
52 
53 const int kModernManifestVersion = 2;
54 const int kPEMOutputColumns = 65;
55 
56 // KEY MARKERS
57 const char kKeyBeginHeaderMarker[] = "-----BEGIN";
58 const char kKeyBeginFooterMarker[] = "-----END";
59 const char kKeyInfoEndMarker[] = "KEY-----";
60 const char kPublic[] = "PUBLIC";
61 const char kPrivate[] = "PRIVATE";
62 
ContainsReservedCharacters(const base::FilePath & path)63 bool ContainsReservedCharacters(const base::FilePath& path) {
64   // We should disallow backslash '\\' as file path separator even on Windows,
65   // because the backslash is not regarded as file path separator on Linux/Mac.
66   // Extensions are cross-platform.
67   // Since FilePath uses backslash '\\' as file path separator on Windows, so we
68   // need to check manually.
69   if (path.value().find('\\') != path.value().npos)
70     return true;
71   return !net::IsSafePortableRelativePath(path);
72 }
73 
74 }  // namespace
75 
76 const char Extension::kMimeType[] = "application/x-chrome-extension";
77 
78 const int Extension::kValidWebExtentSchemes =
79     URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
80 
81 const int Extension::kValidHostPermissionSchemes = URLPattern::SCHEME_CHROMEUI |
82                                                    URLPattern::SCHEME_HTTP |
83                                                    URLPattern::SCHEME_HTTPS |
84                                                    URLPattern::SCHEME_FILE |
85                                                    URLPattern::SCHEME_FTP;
86 
87 //
88 // Extension
89 //
90 
91 // static
Create(const base::FilePath & path,Manifest::Location location,const base::DictionaryValue & value,int flags,std::string * utf8_error)92 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
93                                            Manifest::Location location,
94                                            const base::DictionaryValue& value,
95                                            int flags,
96                                            std::string* utf8_error) {
97   return Extension::Create(path,
98                            location,
99                            value,
100                            flags,
101                            std::string(),  // ID is ignored if empty.
102                            utf8_error);
103 }
104 
105 // TODO(sungguk): Continue removing std::string errors and replacing
106 // with string16. See http://crbug.com/71980.
Create(const base::FilePath & path,Manifest::Location location,const base::DictionaryValue & value,int flags,const std::string & explicit_id,std::string * utf8_error)107 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
108                                            Manifest::Location location,
109                                            const base::DictionaryValue& value,
110                                            int flags,
111                                            const std::string& explicit_id,
112                                            std::string* utf8_error) {
113   DCHECK(utf8_error);
114   string16 error;
115   scoped_ptr<extensions::Manifest> manifest(
116       new extensions::Manifest(
117           location, scoped_ptr<base::DictionaryValue>(value.DeepCopy())));
118 
119   if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error)) {
120     *utf8_error = UTF16ToUTF8(error);
121     return NULL;
122   }
123 
124   std::vector<InstallWarning> install_warnings;
125   if (!manifest->ValidateManifest(utf8_error, &install_warnings)) {
126     return NULL;
127   }
128 
129   scoped_refptr<Extension> extension = new Extension(path, manifest.Pass());
130   extension->install_warnings_.swap(install_warnings);
131 
132   if (!extension->InitFromValue(flags, &error)) {
133     *utf8_error = UTF16ToUTF8(error);
134     return NULL;
135   }
136 
137   return extension;
138 }
139 
140 // static
IdIsValid(const std::string & id)141 bool Extension::IdIsValid(const std::string& id) {
142   // Verify that the id is legal.
143   if (id.size() != (id_util::kIdSize * 2))
144     return false;
145 
146   // We only support lowercase IDs, because IDs can be used as URL components
147   // (where GURL will lowercase it).
148   std::string temp = StringToLowerASCII(id);
149   for (size_t i = 0; i < temp.size(); i++)
150     if (temp[i] < 'a' || temp[i] > 'p')
151       return false;
152 
153   return true;
154 }
155 
GetType() const156 Manifest::Type Extension::GetType() const {
157   return converted_from_user_script() ?
158       Manifest::TYPE_USER_SCRIPT : manifest_->type();
159 }
160 
161 // static
GetResourceURL(const GURL & extension_url,const std::string & relative_path)162 GURL Extension::GetResourceURL(const GURL& extension_url,
163                                const std::string& relative_path) {
164   DCHECK(extension_url.SchemeIs(extensions::kExtensionScheme));
165   DCHECK_EQ("/", extension_url.path());
166 
167   std::string path = relative_path;
168 
169   // If the relative path starts with "/", it is "absolute" relative to the
170   // extension base directory, but extension_url is already specified to refer
171   // to that base directory, so strip the leading "/" if present.
172   if (relative_path.size() > 0 && relative_path[0] == '/')
173     path = relative_path.substr(1);
174 
175   GURL ret_val = GURL(extension_url.spec() + path);
176   DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
177 
178   return ret_val;
179 }
180 
ResourceMatches(const URLPatternSet & pattern_set,const std::string & resource) const181 bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
182                                 const std::string& resource) const {
183   return pattern_set.MatchesURL(extension_url_.Resolve(resource));
184 }
185 
GetResource(const std::string & relative_path) const186 ExtensionResource Extension::GetResource(
187     const std::string& relative_path) const {
188   std::string new_path = relative_path;
189   // We have some legacy data where resources have leading slashes.
190   // See: http://crbug.com/121164
191   if (!new_path.empty() && new_path.at(0) == '/')
192     new_path.erase(0, 1);
193   base::FilePath relative_file_path = base::FilePath::FromUTF8Unsafe(new_path);
194   if (ContainsReservedCharacters(relative_file_path))
195     return ExtensionResource();
196   ExtensionResource r(id(), path(), relative_file_path);
197   if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
198     r.set_follow_symlinks_anywhere();
199   }
200   return r;
201 }
202 
GetResource(const base::FilePath & relative_file_path) const203 ExtensionResource Extension::GetResource(
204     const base::FilePath& relative_file_path) const {
205   if (ContainsReservedCharacters(relative_file_path))
206     return ExtensionResource();
207   ExtensionResource r(id(), path(), relative_file_path);
208   if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
209     r.set_follow_symlinks_anywhere();
210   }
211   return r;
212 }
213 
214 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
215 // util class in base:
216 // http://code.google.com/p/chromium/issues/detail?id=13572
217 // static
ParsePEMKeyBytes(const std::string & input,std::string * output)218 bool Extension::ParsePEMKeyBytes(const std::string& input,
219                                  std::string* output) {
220   DCHECK(output);
221   if (!output)
222     return false;
223   if (input.length() == 0)
224     return false;
225 
226   std::string working = input;
227   if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
228     working = CollapseWhitespaceASCII(working, true);
229     size_t header_pos = working.find(kKeyInfoEndMarker,
230       sizeof(kKeyBeginHeaderMarker) - 1);
231     if (header_pos == std::string::npos)
232       return false;
233     size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
234     size_t end_pos = working.rfind(kKeyBeginFooterMarker);
235     if (end_pos == std::string::npos)
236       return false;
237     if (start_pos >= end_pos)
238       return false;
239 
240     working = working.substr(start_pos, end_pos - start_pos);
241     if (working.length() == 0)
242       return false;
243   }
244 
245   return base::Base64Decode(working, output);
246 }
247 
248 // static
ProducePEM(const std::string & input,std::string * output)249 bool Extension::ProducePEM(const std::string& input, std::string* output) {
250   DCHECK(output);
251   if (input.empty())
252     return false;
253   base::Base64Encode(input, output);
254   return true;
255 }
256 
257 // static
FormatPEMForFileOutput(const std::string & input,std::string * output,bool is_public)258 bool Extension::FormatPEMForFileOutput(const std::string& input,
259                                        std::string* output,
260                                        bool is_public) {
261   DCHECK(output);
262   if (input.length() == 0)
263     return false;
264   *output = "";
265   output->append(kKeyBeginHeaderMarker);
266   output->append(" ");
267   output->append(is_public ? kPublic : kPrivate);
268   output->append(" ");
269   output->append(kKeyInfoEndMarker);
270   output->append("\n");
271   for (size_t i = 0; i < input.length(); ) {
272     int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
273     output->append(input.substr(i, slice));
274     output->append("\n");
275     i += slice;
276   }
277   output->append(kKeyBeginFooterMarker);
278   output->append(" ");
279   output->append(is_public ? kPublic : kPrivate);
280   output->append(" ");
281   output->append(kKeyInfoEndMarker);
282   output->append("\n");
283 
284   return true;
285 }
286 
287 // static
GetBaseURLFromExtensionId(const std::string & extension_id)288 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
289   return GURL(std::string(extensions::kExtensionScheme) +
290               content::kStandardSchemeSeparator + extension_id + "/");
291 }
292 
HasAPIPermission(APIPermission::ID permission) const293 bool Extension::HasAPIPermission(APIPermission::ID permission) const {
294   return PermissionsData::HasAPIPermission(this, permission);
295 }
296 
HasAPIPermission(const std::string & permission_name) const297 bool Extension::HasAPIPermission(const std::string& permission_name) const {
298   return PermissionsData::HasAPIPermission(this, permission_name);
299 }
300 
GetActivePermissions() const301 scoped_refptr<const PermissionSet> Extension::GetActivePermissions() const {
302   return PermissionsData::GetActivePermissions(this);
303 }
304 
ShowConfigureContextMenus() const305 bool Extension::ShowConfigureContextMenus() const {
306   // Don't show context menu for component extensions. We might want to show
307   // options for component extension button but now there is no component
308   // extension with options. All other menu items like uninstall have
309   // no sense for component extensions.
310   return location() != Manifest::COMPONENT;
311 }
312 
OverlapsWithOrigin(const GURL & origin) const313 bool Extension::OverlapsWithOrigin(const GURL& origin) const {
314   if (url() == origin)
315     return true;
316 
317   if (web_extent().is_empty())
318     return false;
319 
320   // Note: patterns and extents ignore port numbers.
321   URLPattern origin_only_pattern(kValidWebExtentSchemes);
322   if (!origin_only_pattern.SetScheme(origin.scheme()))
323     return false;
324   origin_only_pattern.SetHost(origin.host());
325   origin_only_pattern.SetPath("/*");
326 
327   URLPatternSet origin_only_pattern_list;
328   origin_only_pattern_list.AddPattern(origin_only_pattern);
329 
330   return web_extent().OverlapsWith(origin_only_pattern_list);
331 }
332 
RequiresSortOrdinal() const333 bool Extension::RequiresSortOrdinal() const {
334   return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
335 }
336 
ShouldDisplayInAppLauncher() const337 bool Extension::ShouldDisplayInAppLauncher() const {
338   // Only apps should be displayed in the launcher.
339   return is_app() && display_in_launcher_ && !is_ephemeral();
340 }
341 
ShouldDisplayInNewTabPage() const342 bool Extension::ShouldDisplayInNewTabPage() const {
343   // Only apps should be displayed on the NTP.
344   return is_app() && display_in_new_tab_page_ && !is_ephemeral();
345 }
346 
ShouldDisplayInExtensionSettings() const347 bool Extension::ShouldDisplayInExtensionSettings() const {
348   // Don't show for themes since the settings UI isn't really useful for them.
349   if (is_theme())
350     return false;
351 
352   // Don't show component extensions and invisible apps.
353   if (ShouldNotBeVisible())
354     return false;
355 
356   // Always show unpacked extensions and apps.
357   if (Manifest::IsUnpackedLocation(location()))
358     return true;
359 
360   // Unless they are unpacked, never show hosted apps. Note: We intentionally
361   // show packaged apps and platform apps because there are some pieces of
362   // functionality that are only available in chrome://extensions/ but which
363   // are needed for packaged and platform apps. For example, inspecting
364   // background pages. See http://crbug.com/116134.
365   if (is_hosted_app())
366     return false;
367 
368   return true;
369 }
370 
ShouldNotBeVisible() const371 bool Extension::ShouldNotBeVisible() const {
372   // Don't show component extensions because they are only extensions as an
373   // implementation detail of Chrome.
374   if ((location() == Manifest::COMPONENT ||
375        location() == Manifest::EXTERNAL_COMPONENT) &&
376       !CommandLine::ForCurrentProcess()->HasSwitch(
377           switches::kShowComponentExtensionOptions)) {
378     return true;
379   }
380 
381   // Always show unpacked extensions and apps.
382   if (Manifest::IsUnpackedLocation(location()))
383     return false;
384 
385   // Don't show apps that aren't visible in either launcher or ntp.
386   if (is_app() && !ShouldDisplayInAppLauncher() && !ShouldDisplayInNewTabPage())
387     return true;
388 
389   return false;
390 }
391 
GetManifestData(const std::string & key) const392 Extension::ManifestData* Extension::GetManifestData(const std::string& key)
393     const {
394   DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
395   ManifestDataMap::const_iterator iter = manifest_data_.find(key);
396   if (iter != manifest_data_.end())
397     return iter->second.get();
398   return NULL;
399 }
400 
SetManifestData(const std::string & key,Extension::ManifestData * data)401 void Extension::SetManifestData(const std::string& key,
402                                 Extension::ManifestData* data) {
403   DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
404   manifest_data_[key] = linked_ptr<ManifestData>(data);
405 }
406 
location() const407 Manifest::Location Extension::location() const {
408   return manifest_->location();
409 }
410 
id() const411 const std::string& Extension::id() const {
412   return manifest_->extension_id();
413 }
414 
VersionString() const415 const std::string Extension::VersionString() const {
416   return version()->GetString();
417 }
418 
AddInstallWarning(const InstallWarning & new_warning)419 void Extension::AddInstallWarning(const InstallWarning& new_warning) {
420   install_warnings_.push_back(new_warning);
421 }
422 
AddInstallWarnings(const std::vector<InstallWarning> & new_warnings)423 void Extension::AddInstallWarnings(
424     const std::vector<InstallWarning>& new_warnings) {
425   install_warnings_.insert(install_warnings_.end(),
426                            new_warnings.begin(), new_warnings.end());
427 }
428 
is_app() const429 bool Extension::is_app() const {
430   return manifest_->is_app();
431 }
432 
is_platform_app() const433 bool Extension::is_platform_app() const {
434   return manifest_->is_platform_app();
435 }
436 
is_hosted_app() const437 bool Extension::is_hosted_app() const {
438   return manifest()->is_hosted_app();
439 }
440 
is_legacy_packaged_app() const441 bool Extension::is_legacy_packaged_app() const {
442   return manifest()->is_legacy_packaged_app();
443 }
444 
is_extension() const445 bool Extension::is_extension() const {
446   return manifest()->is_extension();
447 }
448 
can_be_incognito_enabled() const449 bool Extension::can_be_incognito_enabled() const {
450   // Only component platform apps are supported in incognito.
451   return !is_platform_app() || location() == Manifest::COMPONENT;
452 }
453 
force_incognito_enabled() const454 bool Extension::force_incognito_enabled() const {
455   return PermissionsData::HasAPIPermission(this, APIPermission::kProxy);
456 }
457 
AddWebExtentPattern(const URLPattern & pattern)458 void Extension::AddWebExtentPattern(const URLPattern& pattern) {
459   extent_.AddPattern(pattern);
460 }
461 
is_theme() const462 bool Extension::is_theme() const {
463   return manifest()->is_theme();
464 }
465 
466 // static
InitExtensionID(extensions::Manifest * manifest,const base::FilePath & path,const std::string & explicit_id,int creation_flags,string16 * error)467 bool Extension::InitExtensionID(extensions::Manifest* manifest,
468                                 const base::FilePath& path,
469                                 const std::string& explicit_id,
470                                 int creation_flags,
471                                 string16* error) {
472   if (!explicit_id.empty()) {
473     manifest->set_extension_id(explicit_id);
474     return true;
475   }
476 
477   if (manifest->HasKey(keys::kPublicKey)) {
478     std::string public_key;
479     std::string public_key_bytes;
480     if (!manifest->GetString(keys::kPublicKey, &public_key) ||
481         !ParsePEMKeyBytes(public_key, &public_key_bytes)) {
482       *error = ASCIIToUTF16(errors::kInvalidKey);
483       return false;
484     }
485     std::string extension_id = id_util::GenerateId(public_key_bytes);
486     manifest->set_extension_id(extension_id);
487     return true;
488   }
489 
490   if (creation_flags & REQUIRE_KEY) {
491     *error = ASCIIToUTF16(errors::kInvalidKey);
492     return false;
493   } else {
494     // If there is a path, we generate the ID from it. This is useful for
495     // development mode, because it keeps the ID stable across restarts and
496     // reloading the extension.
497     std::string extension_id = id_util::GenerateIdForPath(path);
498     if (extension_id.empty()) {
499       NOTREACHED() << "Could not create ID from path.";
500       return false;
501     }
502     manifest->set_extension_id(extension_id);
503     return true;
504   }
505 }
506 
Extension(const base::FilePath & path,scoped_ptr<extensions::Manifest> manifest)507 Extension::Extension(const base::FilePath& path,
508                      scoped_ptr<extensions::Manifest> manifest)
509     : manifest_version_(0),
510       converted_from_user_script_(false),
511       manifest_(manifest.release()),
512       finished_parsing_manifest_(false),
513       display_in_launcher_(true),
514       display_in_new_tab_page_(true),
515       wants_file_access_(false),
516       creation_flags_(0) {
517   DCHECK(path.empty() || path.IsAbsolute());
518   path_ = id_util::MaybeNormalizePath(path);
519 }
520 
~Extension()521 Extension::~Extension() {
522 }
523 
InitFromValue(int flags,string16 * error)524 bool Extension::InitFromValue(int flags, string16* error) {
525   DCHECK(error);
526 
527   creation_flags_ = flags;
528 
529   // Important to load manifest version first because many other features
530   // depend on its value.
531   if (!LoadManifestVersion(error))
532     return false;
533 
534   if (!LoadRequiredFeatures(error))
535     return false;
536 
537   // We don't need to validate because InitExtensionID already did that.
538   manifest_->GetString(keys::kPublicKey, &public_key_);
539 
540   extension_url_ = Extension::GetBaseURLFromExtensionId(id());
541 
542   // Load App settings. LoadExtent at least has to be done before
543   // ParsePermissions(), because the valid permissions depend on what type of
544   // package this is.
545   if (is_app() && !LoadAppFeatures(error))
546     return false;
547 
548   permissions_data_.reset(new PermissionsData);
549   if (!permissions_data_->ParsePermissions(this, error))
550     return false;
551 
552   if (manifest_->HasKey(keys::kConvertedFromUserScript)) {
553     manifest_->GetBoolean(keys::kConvertedFromUserScript,
554                           &converted_from_user_script_);
555   }
556 
557   if (!LoadSharedFeatures(error))
558     return false;
559 
560   finished_parsing_manifest_ = true;
561 
562   permissions_data_->InitializeManifestPermissions(this);
563   permissions_data_->FinalizePermissions(this);
564 
565   return true;
566 }
567 
LoadRequiredFeatures(string16 * error)568 bool Extension::LoadRequiredFeatures(string16* error) {
569   if (!LoadName(error) ||
570       !LoadVersion(error))
571     return false;
572   return true;
573 }
574 
LoadName(string16 * error)575 bool Extension::LoadName(string16* error) {
576   string16 localized_name;
577   if (!manifest_->GetString(keys::kName, &localized_name)) {
578     *error = ASCIIToUTF16(errors::kInvalidName);
579     return false;
580   }
581   non_localized_name_ = UTF16ToUTF8(localized_name);
582   base::i18n::AdjustStringForLocaleDirection(&localized_name);
583   name_ = UTF16ToUTF8(localized_name);
584   return true;
585 }
586 
LoadVersion(string16 * error)587 bool Extension::LoadVersion(string16* error) {
588   std::string version_str;
589   if (!manifest_->GetString(keys::kVersion, &version_str)) {
590     *error = ASCIIToUTF16(errors::kInvalidVersion);
591     return false;
592   }
593   version_.reset(new Version(version_str));
594   if (!version_->IsValid() || version_->components().size() > 4) {
595     *error = ASCIIToUTF16(errors::kInvalidVersion);
596     return false;
597   }
598   return true;
599 }
600 
LoadAppFeatures(string16 * error)601 bool Extension::LoadAppFeatures(string16* error) {
602   if (!LoadExtent(keys::kWebURLs, &extent_,
603                   errors::kInvalidWebURLs, errors::kInvalidWebURL, error)) {
604     return false;
605   }
606   if (manifest_->HasKey(keys::kDisplayInLauncher) &&
607       !manifest_->GetBoolean(keys::kDisplayInLauncher, &display_in_launcher_)) {
608     *error = ASCIIToUTF16(errors::kInvalidDisplayInLauncher);
609     return false;
610   }
611   if (manifest_->HasKey(keys::kDisplayInNewTabPage)) {
612     if (!manifest_->GetBoolean(keys::kDisplayInNewTabPage,
613                                &display_in_new_tab_page_)) {
614       *error = ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage);
615       return false;
616     }
617   } else {
618     // Inherit default from display_in_launcher property.
619     display_in_new_tab_page_ = display_in_launcher_;
620   }
621   return true;
622 }
623 
LoadExtent(const char * key,URLPatternSet * extent,const char * list_error,const char * value_error,string16 * error)624 bool Extension::LoadExtent(const char* key,
625                            URLPatternSet* extent,
626                            const char* list_error,
627                            const char* value_error,
628                            string16* error) {
629   const base::Value* temp_pattern_value = NULL;
630   if (!manifest_->Get(key, &temp_pattern_value))
631     return true;
632 
633   const base::ListValue* pattern_list = NULL;
634   if (!temp_pattern_value->GetAsList(&pattern_list)) {
635     *error = ASCIIToUTF16(list_error);
636     return false;
637   }
638 
639   for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
640     std::string pattern_string;
641     if (!pattern_list->GetString(i, &pattern_string)) {
642       *error = ErrorUtils::FormatErrorMessageUTF16(value_error,
643                                                    base::UintToString(i),
644                                                    errors::kExpectString);
645       return false;
646     }
647 
648     URLPattern pattern(kValidWebExtentSchemes);
649     URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
650     if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
651       pattern_string += "/";
652       parse_result = pattern.Parse(pattern_string);
653     }
654 
655     if (parse_result != URLPattern::PARSE_SUCCESS) {
656       *error = ErrorUtils::FormatErrorMessageUTF16(
657           value_error,
658           base::UintToString(i),
659           URLPattern::GetParseResultString(parse_result));
660       return false;
661     }
662 
663     // Do not allow authors to claim "<all_urls>".
664     if (pattern.match_all_urls()) {
665       *error = ErrorUtils::FormatErrorMessageUTF16(
666           value_error,
667           base::UintToString(i),
668           errors::kCannotClaimAllURLsInExtent);
669       return false;
670     }
671 
672     // Do not allow authors to claim "*" for host.
673     if (pattern.host().empty()) {
674       *error = ErrorUtils::FormatErrorMessageUTF16(
675           value_error,
676           base::UintToString(i),
677           errors::kCannotClaimAllHostsInExtent);
678       return false;
679     }
680 
681     // We do not allow authors to put wildcards in their paths. Instead, we
682     // imply one at the end.
683     if (pattern.path().find('*') != std::string::npos) {
684       *error = ErrorUtils::FormatErrorMessageUTF16(
685           value_error,
686           base::UintToString(i),
687           errors::kNoWildCardsInPaths);
688       return false;
689     }
690     pattern.SetPath(pattern.path() + '*');
691 
692     extent->AddPattern(pattern);
693   }
694 
695   return true;
696 }
697 
LoadSharedFeatures(string16 * error)698 bool Extension::LoadSharedFeatures(string16* error) {
699   if (!LoadDescription(error) ||
700       !ManifestHandler::ParseExtension(this, error) ||
701       !LoadShortName(error))
702     return false;
703 
704   return true;
705 }
706 
LoadDescription(string16 * error)707 bool Extension::LoadDescription(string16* error) {
708   if (manifest_->HasKey(keys::kDescription) &&
709       !manifest_->GetString(keys::kDescription, &description_)) {
710     *error = ASCIIToUTF16(errors::kInvalidDescription);
711     return false;
712   }
713   return true;
714 }
715 
LoadManifestVersion(string16 * error)716 bool Extension::LoadManifestVersion(string16* error) {
717   // Get the original value out of the dictionary so that we can validate it
718   // more strictly.
719   if (manifest_->value()->HasKey(keys::kManifestVersion)) {
720     int manifest_version = 1;
721     if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
722         manifest_version < 1) {
723       *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
724       return false;
725     }
726   }
727 
728   manifest_version_ = manifest_->GetManifestVersion();
729   if (manifest_version_ < kModernManifestVersion &&
730       ((creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
731         !CommandLine::ForCurrentProcess()->HasSwitch(
732             switches::kAllowLegacyExtensionManifests)) ||
733        GetType() == Manifest::TYPE_PLATFORM_APP)) {
734     *error = ErrorUtils::FormatErrorMessageUTF16(
735         errors::kInvalidManifestVersionOld,
736         base::IntToString(kModernManifestVersion),
737         is_platform_app() ? "apps" : "extensions");
738     return false;
739   }
740 
741   return true;
742 }
743 
LoadShortName(string16 * error)744 bool Extension::LoadShortName(string16* error) {
745   if (manifest_->HasKey(keys::kShortName)) {
746     string16 localized_short_name;
747     if (!manifest_->GetString(keys::kShortName, &localized_short_name) ||
748         localized_short_name.empty()) {
749       *error = ASCIIToUTF16(errors::kInvalidShortName);
750       return false;
751     }
752 
753     base::i18n::AdjustStringForLocaleDirection(&localized_short_name);
754     short_name_ = UTF16ToUTF8(localized_short_name);
755   } else {
756     short_name_ = name_;
757   }
758   return true;
759 }
760 
ExtensionInfo(const base::DictionaryValue * manifest,const std::string & id,const base::FilePath & path,Manifest::Location location)761 ExtensionInfo::ExtensionInfo(const base::DictionaryValue* manifest,
762                              const std::string& id,
763                              const base::FilePath& path,
764                              Manifest::Location location)
765     : extension_id(id),
766       extension_path(path),
767       extension_location(location) {
768   if (manifest)
769     extension_manifest.reset(manifest->DeepCopy());
770 }
771 
~ExtensionInfo()772 ExtensionInfo::~ExtensionInfo() {}
773 
InstalledExtensionInfo(const Extension * extension,bool is_update,const std::string & old_name)774 InstalledExtensionInfo::InstalledExtensionInfo(
775     const Extension* extension,
776     bool is_update,
777     const std::string& old_name)
778     : extension(extension),
779       is_update(is_update),
780       old_name(old_name) {}
781 
UnloadedExtensionInfo(const Extension * extension,UnloadedExtensionInfo::Reason reason)782 UnloadedExtensionInfo::UnloadedExtensionInfo(
783     const Extension* extension,
784     UnloadedExtensionInfo::Reason reason)
785     : reason(reason),
786       extension(extension) {}
787 
UpdatedExtensionPermissionsInfo(const Extension * extension,const PermissionSet * permissions,Reason reason)788 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
789     const Extension* extension,
790     const PermissionSet* permissions,
791     Reason reason)
792     : reason(reason),
793       extension(extension),
794       permissions(permissions) {}
795 
796 }   // namespace extensions
797