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