Release the Settings API.
[chromium-blink-merge.git] / extensions / common / extension.cc
blob14f57636119db9d4f83d7145b37ff905281ae30a
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.
5 #include "extensions/common/extension.h"
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 "net/base/filename_util.h"
38 #include "url/url_util.h"
40 #if defined(OS_WIN)
41 #include "grit/generated_resources.h"
42 #endif
44 namespace extensions {
46 namespace keys = manifest_keys;
47 namespace values = manifest_values;
48 namespace errors = manifest_errors;
50 namespace {
52 const int kModernManifestVersion = 2;
53 const int kPEMOutputColumns = 64;
55 // KEY MARKERS
56 const char kKeyBeginHeaderMarker[] = "-----BEGIN";
57 const char kKeyBeginFooterMarker[] = "-----END";
58 const char kKeyInfoEndMarker[] = "KEY-----";
59 const char kPublic[] = "PUBLIC";
60 const char kPrivate[] = "PRIVATE";
62 bool ContainsReservedCharacters(const base::FilePath& path) {
63 // We should disallow backslash '\\' as file path separator even on Windows,
64 // because the backslash is not regarded as file path separator on Linux/Mac.
65 // Extensions are cross-platform.
66 // Since FilePath uses backslash '\\' as file path separator on Windows, so we
67 // need to check manually.
68 if (path.value().find('\\') != path.value().npos)
69 return true;
70 return !net::IsSafePortableRelativePath(path);
73 } // namespace
75 const char Extension::kMimeType[] = "application/x-chrome-extension";
77 const int Extension::kValidWebExtentSchemes =
78 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
80 const int Extension::kValidHostPermissionSchemes = URLPattern::SCHEME_CHROMEUI |
81 URLPattern::SCHEME_HTTP |
82 URLPattern::SCHEME_HTTPS |
83 URLPattern::SCHEME_FILE |
84 URLPattern::SCHEME_FTP;
87 // Extension
90 // static
91 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
92 Manifest::Location location,
93 const base::DictionaryValue& value,
94 int flags,
95 std::string* utf8_error) {
96 return Extension::Create(path,
97 location,
98 value,
99 flags,
100 std::string(), // ID is ignored if empty.
101 utf8_error);
104 // TODO(sungguk): Continue removing std::string errors and replacing
105 // with base::string16. See http://crbug.com/71980.
106 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
107 Manifest::Location location,
108 const base::DictionaryValue& value,
109 int flags,
110 const std::string& explicit_id,
111 std::string* utf8_error) {
112 DCHECK(utf8_error);
113 base::string16 error;
114 scoped_ptr<extensions::Manifest> manifest(
115 new extensions::Manifest(
116 location, scoped_ptr<base::DictionaryValue>(value.DeepCopy())));
118 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error)) {
119 *utf8_error = base::UTF16ToUTF8(error);
120 return NULL;
123 std::vector<InstallWarning> install_warnings;
124 if (!manifest->ValidateManifest(utf8_error, &install_warnings)) {
125 return NULL;
128 scoped_refptr<Extension> extension = new Extension(path, manifest.Pass());
129 extension->install_warnings_.swap(install_warnings);
131 if (!extension->InitFromValue(flags, &error)) {
132 *utf8_error = base::UTF16ToUTF8(error);
133 return NULL;
136 return extension;
139 // static
140 bool Extension::IdIsValid(const std::string& id) {
141 // Verify that the id is legal.
142 if (id.size() != (id_util::kIdSize * 2))
143 return false;
145 // We only support lowercase IDs, because IDs can be used as URL components
146 // (where GURL will lowercase it).
147 std::string temp = StringToLowerASCII(id);
148 for (size_t i = 0; i < temp.size(); i++)
149 if (temp[i] < 'a' || temp[i] > 'p')
150 return false;
152 return true;
155 Manifest::Type Extension::GetType() const {
156 return converted_from_user_script() ?
157 Manifest::TYPE_USER_SCRIPT : manifest_->type();
160 // static
161 GURL Extension::GetResourceURL(const GURL& extension_url,
162 const std::string& relative_path) {
163 DCHECK(extension_url.SchemeIs(extensions::kExtensionScheme));
164 DCHECK_EQ("/", extension_url.path());
166 std::string path = relative_path;
168 // If the relative path starts with "/", it is "absolute" relative to the
169 // extension base directory, but extension_url is already specified to refer
170 // to that base directory, so strip the leading "/" if present.
171 if (relative_path.size() > 0 && relative_path[0] == '/')
172 path = relative_path.substr(1);
174 GURL ret_val = GURL(extension_url.spec() + path);
175 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
177 return ret_val;
180 bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
181 const std::string& resource) const {
182 return pattern_set.MatchesURL(extension_url_.Resolve(resource));
185 ExtensionResource Extension::GetResource(
186 const std::string& relative_path) const {
187 std::string new_path = relative_path;
188 // We have some legacy data where resources have leading slashes.
189 // See: http://crbug.com/121164
190 if (!new_path.empty() && new_path.at(0) == '/')
191 new_path.erase(0, 1);
192 base::FilePath relative_file_path = base::FilePath::FromUTF8Unsafe(new_path);
193 if (ContainsReservedCharacters(relative_file_path))
194 return ExtensionResource();
195 ExtensionResource r(id(), path(), relative_file_path);
196 if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
197 r.set_follow_symlinks_anywhere();
199 return r;
202 ExtensionResource Extension::GetResource(
203 const base::FilePath& relative_file_path) const {
204 if (ContainsReservedCharacters(relative_file_path))
205 return ExtensionResource();
206 ExtensionResource r(id(), path(), relative_file_path);
207 if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
208 r.set_follow_symlinks_anywhere();
210 return r;
213 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
214 // util class in base:
215 // http://code.google.com/p/chromium/issues/detail?id=13572
216 // static
217 bool Extension::ParsePEMKeyBytes(const std::string& input,
218 std::string* output) {
219 DCHECK(output);
220 if (!output)
221 return false;
222 if (input.length() == 0)
223 return false;
225 std::string working = input;
226 if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
227 working = base::CollapseWhitespaceASCII(working, true);
228 size_t header_pos = working.find(kKeyInfoEndMarker,
229 sizeof(kKeyBeginHeaderMarker) - 1);
230 if (header_pos == std::string::npos)
231 return false;
232 size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
233 size_t end_pos = working.rfind(kKeyBeginFooterMarker);
234 if (end_pos == std::string::npos)
235 return false;
236 if (start_pos >= end_pos)
237 return false;
239 working = working.substr(start_pos, end_pos - start_pos);
240 if (working.length() == 0)
241 return false;
244 return base::Base64Decode(working, output);
247 // static
248 bool Extension::ProducePEM(const std::string& input, std::string* output) {
249 DCHECK(output);
250 if (input.empty())
251 return false;
252 base::Base64Encode(input, output);
253 return true;
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;
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");
283 return true;
286 // static
287 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
288 return GURL(std::string(extensions::kExtensionScheme) +
289 content::kStandardSchemeSeparator + extension_id + "/");
292 bool Extension::HasAPIPermission(APIPermission::ID permission) const {
293 return PermissionsData::HasAPIPermission(this, permission);
296 bool Extension::HasAPIPermission(const std::string& permission_name) const {
297 return PermissionsData::HasAPIPermission(this, permission_name);
300 scoped_refptr<const PermissionSet> Extension::GetActivePermissions() const {
301 return PermissionsData::GetActivePermissions(this);
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 location() != Manifest::EXTERNAL_COMPONENT;
313 bool Extension::OverlapsWithOrigin(const GURL& origin) const {
314 if (url() == origin)
315 return true;
317 if (web_extent().is_empty())
318 return false;
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("/*");
327 URLPatternSet origin_only_pattern_list;
328 origin_only_pattern_list.AddPattern(origin_only_pattern);
330 return web_extent().OverlapsWith(origin_only_pattern_list);
333 bool Extension::RequiresSortOrdinal() const {
334 return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
337 bool Extension::ShouldDisplayInAppLauncher() const {
338 // Only apps should be displayed in the launcher.
339 return is_app() && display_in_launcher_ && !is_ephemeral();
342 bool Extension::ShouldDisplayInNewTabPage() const {
343 // Only apps should be displayed on the NTP.
344 return is_app() && display_in_new_tab_page_ && !is_ephemeral();
347 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;
352 // Don't show component extensions and invisible apps.
353 if (ShouldNotBeVisible())
354 return false;
356 // Always show unpacked extensions and apps.
357 if (Manifest::IsUnpackedLocation(location()))
358 return true;
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;
368 return true;
371 bool Extension::ShouldNotBeVisible() const {
372 // Don't show component extensions because they are only extensions as an
373 // implementation detail of Chrome.
374 if (extensions::Manifest::IsComponentLocation(location()) &&
375 !CommandLine::ForCurrentProcess()->HasSwitch(
376 switches::kShowComponentExtensionOptions)) {
377 return true;
380 // Always show unpacked extensions and apps.
381 if (Manifest::IsUnpackedLocation(location()))
382 return false;
384 // Don't show apps that aren't visible in either launcher or ntp.
385 if (is_app() && !ShouldDisplayInAppLauncher() && !ShouldDisplayInNewTabPage())
386 return true;
388 return false;
391 Extension::ManifestData* Extension::GetManifestData(const std::string& key)
392 const {
393 DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
394 ManifestDataMap::const_iterator iter = manifest_data_.find(key);
395 if (iter != manifest_data_.end())
396 return iter->second.get();
397 return NULL;
400 void Extension::SetManifestData(const std::string& key,
401 Extension::ManifestData* data) {
402 DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
403 manifest_data_[key] = linked_ptr<ManifestData>(data);
406 Manifest::Location Extension::location() const {
407 return manifest_->location();
410 const std::string& Extension::id() const {
411 return manifest_->extension_id();
414 const std::string Extension::VersionString() const {
415 return version()->GetString();
418 void Extension::AddInstallWarning(const InstallWarning& new_warning) {
419 install_warnings_.push_back(new_warning);
422 void Extension::AddInstallWarnings(
423 const std::vector<InstallWarning>& new_warnings) {
424 install_warnings_.insert(install_warnings_.end(),
425 new_warnings.begin(), new_warnings.end());
428 bool Extension::is_app() const {
429 return manifest_->is_app();
432 bool Extension::is_platform_app() const {
433 return manifest_->is_platform_app();
436 bool Extension::is_hosted_app() const {
437 return manifest()->is_hosted_app();
440 bool Extension::is_legacy_packaged_app() const {
441 return manifest()->is_legacy_packaged_app();
444 bool Extension::is_extension() const {
445 return manifest()->is_extension();
448 bool Extension::can_be_incognito_enabled() const {
449 // Only component platform apps are supported in incognito.
450 return !is_platform_app() || location() == Manifest::COMPONENT;
453 void Extension::AddWebExtentPattern(const URLPattern& pattern) {
454 // Bookmark apps are permissionless.
455 if (from_bookmark())
456 return;
458 extent_.AddPattern(pattern);
461 bool Extension::is_theme() const {
462 return manifest()->is_theme();
465 // static
466 bool Extension::InitExtensionID(extensions::Manifest* manifest,
467 const base::FilePath& path,
468 const std::string& explicit_id,
469 int creation_flags,
470 base::string16* error) {
471 if (!explicit_id.empty()) {
472 manifest->set_extension_id(explicit_id);
473 return true;
476 if (manifest->HasKey(keys::kPublicKey)) {
477 std::string public_key;
478 std::string public_key_bytes;
479 if (!manifest->GetString(keys::kPublicKey, &public_key) ||
480 !ParsePEMKeyBytes(public_key, &public_key_bytes)) {
481 *error = base::ASCIIToUTF16(errors::kInvalidKey);
482 return false;
484 std::string extension_id = id_util::GenerateId(public_key_bytes);
485 manifest->set_extension_id(extension_id);
486 return true;
489 if (creation_flags & REQUIRE_KEY) {
490 *error = base::ASCIIToUTF16(errors::kInvalidKey);
491 return false;
492 } else {
493 // If there is a path, we generate the ID from it. This is useful for
494 // development mode, because it keeps the ID stable across restarts and
495 // reloading the extension.
496 std::string extension_id = id_util::GenerateIdForPath(path);
497 if (extension_id.empty()) {
498 NOTREACHED() << "Could not create ID from path.";
499 return false;
501 manifest->set_extension_id(extension_id);
502 return true;
506 Extension::Extension(const base::FilePath& path,
507 scoped_ptr<extensions::Manifest> manifest)
508 : manifest_version_(0),
509 converted_from_user_script_(false),
510 manifest_(manifest.release()),
511 finished_parsing_manifest_(false),
512 display_in_launcher_(true),
513 display_in_new_tab_page_(true),
514 wants_file_access_(false),
515 creation_flags_(0) {
516 DCHECK(path.empty() || path.IsAbsolute());
517 path_ = id_util::MaybeNormalizePath(path);
520 Extension::~Extension() {
523 bool Extension::InitFromValue(int flags, base::string16* error) {
524 DCHECK(error);
526 creation_flags_ = flags;
528 // Important to load manifest version first because many other features
529 // depend on its value.
530 if (!LoadManifestVersion(error))
531 return false;
533 if (!LoadRequiredFeatures(error))
534 return false;
536 // We don't need to validate because InitExtensionID already did that.
537 manifest_->GetString(keys::kPublicKey, &public_key_);
539 extension_url_ = Extension::GetBaseURLFromExtensionId(id());
541 // Load App settings. LoadExtent at least has to be done before
542 // ParsePermissions(), because the valid permissions depend on what type of
543 // package this is.
544 if (is_app() && !LoadAppFeatures(error))
545 return false;
547 permissions_data_.reset(new PermissionsData);
548 if (!permissions_data_->ParsePermissions(this, error))
549 return false;
551 if (manifest_->HasKey(keys::kConvertedFromUserScript)) {
552 manifest_->GetBoolean(keys::kConvertedFromUserScript,
553 &converted_from_user_script_);
556 if (!LoadSharedFeatures(error))
557 return false;
559 finished_parsing_manifest_ = true;
561 permissions_data_->InitializeManifestPermissions(this);
562 permissions_data_->FinalizePermissions(this);
564 return true;
567 bool Extension::LoadRequiredFeatures(base::string16* error) {
568 if (!LoadName(error) ||
569 !LoadVersion(error))
570 return false;
571 return true;
574 bool Extension::LoadName(base::string16* error) {
575 base::string16 localized_name;
576 if (!manifest_->GetString(keys::kName, &localized_name)) {
577 *error = base::ASCIIToUTF16(errors::kInvalidName);
578 return false;
580 non_localized_name_ = base::UTF16ToUTF8(localized_name);
581 base::i18n::AdjustStringForLocaleDirection(&localized_name);
582 name_ = base::UTF16ToUTF8(localized_name);
583 return true;
586 bool Extension::LoadVersion(base::string16* error) {
587 std::string version_str;
588 if (!manifest_->GetString(keys::kVersion, &version_str)) {
589 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
590 return false;
592 version_.reset(new Version(version_str));
593 if (!version_->IsValid() || version_->components().size() > 4) {
594 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
595 return false;
597 return true;
600 bool Extension::LoadAppFeatures(base::string16* error) {
601 if (!LoadExtent(keys::kWebURLs, &extent_,
602 errors::kInvalidWebURLs, errors::kInvalidWebURL, error)) {
603 return false;
605 if (manifest_->HasKey(keys::kDisplayInLauncher) &&
606 !manifest_->GetBoolean(keys::kDisplayInLauncher, &display_in_launcher_)) {
607 *error = base::ASCIIToUTF16(errors::kInvalidDisplayInLauncher);
608 return false;
610 if (manifest_->HasKey(keys::kDisplayInNewTabPage)) {
611 if (!manifest_->GetBoolean(keys::kDisplayInNewTabPage,
612 &display_in_new_tab_page_)) {
613 *error = base::ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage);
614 return false;
616 } else {
617 // Inherit default from display_in_launcher property.
618 display_in_new_tab_page_ = display_in_launcher_;
620 return true;
623 bool Extension::LoadExtent(const char* key,
624 URLPatternSet* extent,
625 const char* list_error,
626 const char* value_error,
627 base::string16* error) {
628 const base::Value* temp_pattern_value = NULL;
629 if (!manifest_->Get(key, &temp_pattern_value))
630 return true;
632 const base::ListValue* pattern_list = NULL;
633 if (!temp_pattern_value->GetAsList(&pattern_list)) {
634 *error = base::ASCIIToUTF16(list_error);
635 return false;
638 for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
639 std::string pattern_string;
640 if (!pattern_list->GetString(i, &pattern_string)) {
641 *error = ErrorUtils::FormatErrorMessageUTF16(value_error,
642 base::UintToString(i),
643 errors::kExpectString);
644 return false;
647 URLPattern pattern(kValidWebExtentSchemes);
648 URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
649 if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
650 pattern_string += "/";
651 parse_result = pattern.Parse(pattern_string);
654 if (parse_result != URLPattern::PARSE_SUCCESS) {
655 *error = ErrorUtils::FormatErrorMessageUTF16(
656 value_error,
657 base::UintToString(i),
658 URLPattern::GetParseResultString(parse_result));
659 return false;
662 // Do not allow authors to claim "<all_urls>".
663 if (pattern.match_all_urls()) {
664 *error = ErrorUtils::FormatErrorMessageUTF16(
665 value_error,
666 base::UintToString(i),
667 errors::kCannotClaimAllURLsInExtent);
668 return false;
671 // Do not allow authors to claim "*" for host.
672 if (pattern.host().empty()) {
673 *error = ErrorUtils::FormatErrorMessageUTF16(
674 value_error,
675 base::UintToString(i),
676 errors::kCannotClaimAllHostsInExtent);
677 return false;
680 // We do not allow authors to put wildcards in their paths. Instead, we
681 // imply one at the end.
682 if (pattern.path().find('*') != std::string::npos) {
683 *error = ErrorUtils::FormatErrorMessageUTF16(
684 value_error,
685 base::UintToString(i),
686 errors::kNoWildCardsInPaths);
687 return false;
689 pattern.SetPath(pattern.path() + '*');
691 extent->AddPattern(pattern);
694 return true;
697 bool Extension::LoadSharedFeatures(base::string16* error) {
698 if (!LoadDescription(error) ||
699 !ManifestHandler::ParseExtension(this, error) ||
700 !LoadShortName(error))
701 return false;
703 return true;
706 bool Extension::LoadDescription(base::string16* error) {
707 if (manifest_->HasKey(keys::kDescription) &&
708 !manifest_->GetString(keys::kDescription, &description_)) {
709 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
710 return false;
712 return true;
715 bool Extension::LoadManifestVersion(base::string16* error) {
716 // Get the original value out of the dictionary so that we can validate it
717 // more strictly.
718 if (manifest_->value()->HasKey(keys::kManifestVersion)) {
719 int manifest_version = 1;
720 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
721 manifest_version < 1) {
722 *error = base::ASCIIToUTF16(errors::kInvalidManifestVersion);
723 return false;
727 manifest_version_ = manifest_->GetManifestVersion();
728 if (manifest_version_ < kModernManifestVersion &&
729 ((creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
730 !CommandLine::ForCurrentProcess()->HasSwitch(
731 switches::kAllowLegacyExtensionManifests)) ||
732 GetType() == Manifest::TYPE_PLATFORM_APP)) {
733 *error = ErrorUtils::FormatErrorMessageUTF16(
734 errors::kInvalidManifestVersionOld,
735 base::IntToString(kModernManifestVersion),
736 is_platform_app() ? "apps" : "extensions");
737 return false;
740 return true;
743 bool Extension::LoadShortName(base::string16* error) {
744 if (manifest_->HasKey(keys::kShortName)) {
745 base::string16 localized_short_name;
746 if (!manifest_->GetString(keys::kShortName, &localized_short_name) ||
747 localized_short_name.empty()) {
748 *error = base::ASCIIToUTF16(errors::kInvalidShortName);
749 return false;
752 base::i18n::AdjustStringForLocaleDirection(&localized_short_name);
753 short_name_ = base::UTF16ToUTF8(localized_short_name);
754 } else {
755 short_name_ = name_;
757 return true;
760 ExtensionInfo::ExtensionInfo(const base::DictionaryValue* manifest,
761 const std::string& id,
762 const base::FilePath& path,
763 Manifest::Location location)
764 : extension_id(id),
765 extension_path(path),
766 extension_location(location) {
767 if (manifest)
768 extension_manifest.reset(manifest->DeepCopy());
771 ExtensionInfo::~ExtensionInfo() {}
773 InstalledExtensionInfo::InstalledExtensionInfo(
774 const Extension* extension,
775 bool is_update,
776 const std::string& old_name)
777 : extension(extension),
778 is_update(is_update),
779 old_name(old_name) {}
781 UnloadedExtensionInfo::UnloadedExtensionInfo(
782 const Extension* extension,
783 UnloadedExtensionInfo::Reason reason)
784 : reason(reason),
785 extension(extension) {}
787 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
788 const Extension* extension,
789 const PermissionSet* permissions,
790 Reason reason)
791 : reason(reason),
792 extension(extension),
793 permissions(permissions) {}
795 } // namespace extensions