Revert 239759 "The comment in base64.h implies that base::Base64..."
[chromium-blink-merge.git] / extensions / common / extension.cc
blob10e065b97f791fa7c270c748dd59f85714407db7
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 "grit/theme_resources.h"
38 #include "net/base/net_util.h"
39 #include "url/url_util.h"
41 #if defined(OS_WIN)
42 #include "grit/generated_resources.h"
43 #endif
45 namespace extensions {
47 namespace keys = manifest_keys;
48 namespace values = manifest_values;
49 namespace errors = manifest_errors;
51 namespace {
53 const int kModernManifestVersion = 2;
54 const int kPEMOutputColumns = 65;
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";
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);
74 } // namespace
76 const char Extension::kMimeType[] = "application/x-chrome-extension";
78 const int Extension::kValidWebExtentSchemes =
79 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
81 const int Extension::kValidHostPermissionSchemes = URLPattern::SCHEME_CHROMEUI |
82 URLPattern::SCHEME_HTTP |
83 URLPattern::SCHEME_HTTPS |
84 URLPattern::SCHEME_FILE |
85 URLPattern::SCHEME_FTP;
88 // Extension
91 // static
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);
105 // TODO(sungguk): Continue removing std::string errors and replacing
106 // with string16. See http://crbug.com/71980.
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())));
119 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error)) {
120 *utf8_error = UTF16ToUTF8(error);
121 return NULL;
124 std::vector<InstallWarning> install_warnings;
125 if (!manifest->ValidateManifest(utf8_error, &install_warnings)) {
126 return NULL;
129 scoped_refptr<Extension> extension = new Extension(path, manifest.Pass());
130 extension->install_warnings_.swap(install_warnings);
132 if (!extension->InitFromValue(flags, &error)) {
133 *utf8_error = UTF16ToUTF8(error);
134 return NULL;
137 return extension;
140 // static
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;
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;
153 return true;
156 Manifest::Type Extension::GetType() const {
157 return converted_from_user_script() ?
158 Manifest::TYPE_USER_SCRIPT : manifest_->type();
161 // static
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());
167 std::string path = relative_path;
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);
175 GURL ret_val = GURL(extension_url.spec() + path);
176 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
178 return ret_val;
181 bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
182 const std::string& resource) const {
183 return pattern_set.MatchesURL(extension_url_.Resolve(resource));
186 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();
200 return r;
203 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();
211 return r;
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
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;
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;
240 working = working.substr(start_pos, end_pos - start_pos);
241 if (working.length() == 0)
242 return false;
245 return base::Base64Decode(working, output);
248 // static
249 bool Extension::ProducePEM(const std::string& input, std::string* output) {
250 DCHECK(output);
251 return (input.length() == 0) ? false : base::Base64Encode(input, output);
254 // static
255 bool Extension::FormatPEMForFileOutput(const std::string& input,
256 std::string* output,
257 bool is_public) {
258 DCHECK(output);
259 if (input.length() == 0)
260 return false;
261 *output = "";
262 output->append(kKeyBeginHeaderMarker);
263 output->append(" ");
264 output->append(is_public ? kPublic : kPrivate);
265 output->append(" ");
266 output->append(kKeyInfoEndMarker);
267 output->append("\n");
268 for (size_t i = 0; i < input.length(); ) {
269 int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
270 output->append(input.substr(i, slice));
271 output->append("\n");
272 i += slice;
274 output->append(kKeyBeginFooterMarker);
275 output->append(" ");
276 output->append(is_public ? kPublic : kPrivate);
277 output->append(" ");
278 output->append(kKeyInfoEndMarker);
279 output->append("\n");
281 return true;
284 // static
285 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
286 return GURL(std::string(extensions::kExtensionScheme) +
287 content::kStandardSchemeSeparator + extension_id + "/");
290 bool Extension::HasAPIPermission(APIPermission::ID permission) const {
291 return PermissionsData::HasAPIPermission(this, permission);
294 bool Extension::HasAPIPermission(const std::string& permission_name) const {
295 return PermissionsData::HasAPIPermission(this, permission_name);
298 scoped_refptr<const PermissionSet> Extension::GetActivePermissions() const {
299 return PermissionsData::GetActivePermissions(this);
302 bool Extension::ShowConfigureContextMenus() const {
303 // Don't show context menu for component extensions. We might want to show
304 // options for component extension button but now there is no component
305 // extension with options. All other menu items like uninstall have
306 // no sense for component extensions.
307 return location() != Manifest::COMPONENT;
310 bool Extension::OverlapsWithOrigin(const GURL& origin) const {
311 if (url() == origin)
312 return true;
314 if (web_extent().is_empty())
315 return false;
317 // Note: patterns and extents ignore port numbers.
318 URLPattern origin_only_pattern(kValidWebExtentSchemes);
319 if (!origin_only_pattern.SetScheme(origin.scheme()))
320 return false;
321 origin_only_pattern.SetHost(origin.host());
322 origin_only_pattern.SetPath("/*");
324 URLPatternSet origin_only_pattern_list;
325 origin_only_pattern_list.AddPattern(origin_only_pattern);
327 return web_extent().OverlapsWith(origin_only_pattern_list);
330 bool Extension::RequiresSortOrdinal() const {
331 return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
334 bool Extension::ShouldDisplayInAppLauncher() const {
335 // Only apps should be displayed in the launcher.
336 return is_app() && display_in_launcher_ && !is_ephemeral();
339 bool Extension::ShouldDisplayInNewTabPage() const {
340 // Only apps should be displayed on the NTP.
341 return is_app() && display_in_new_tab_page_ && !is_ephemeral();
344 bool Extension::ShouldDisplayInExtensionSettings() const {
345 // Don't show for themes since the settings UI isn't really useful for them.
346 if (is_theme())
347 return false;
349 // Don't show component extensions and invisible apps.
350 if (ShouldNotBeVisible())
351 return false;
353 // Always show unpacked extensions and apps.
354 if (Manifest::IsUnpackedLocation(location()))
355 return true;
357 // Unless they are unpacked, never show hosted apps. Note: We intentionally
358 // show packaged apps and platform apps because there are some pieces of
359 // functionality that are only available in chrome://extensions/ but which
360 // are needed for packaged and platform apps. For example, inspecting
361 // background pages. See http://crbug.com/116134.
362 if (is_hosted_app())
363 return false;
365 return true;
368 bool Extension::ShouldNotBeVisible() const {
369 // Don't show component extensions because they are only extensions as an
370 // implementation detail of Chrome.
371 if ((location() == Manifest::COMPONENT ||
372 location() == Manifest::EXTERNAL_COMPONENT) &&
373 !CommandLine::ForCurrentProcess()->HasSwitch(
374 switches::kShowComponentExtensionOptions)) {
375 return true;
378 // Always show unpacked extensions and apps.
379 if (Manifest::IsUnpackedLocation(location()))
380 return false;
382 // Don't show apps that aren't visible in either launcher or ntp.
383 if (is_app() && !ShouldDisplayInAppLauncher() && !ShouldDisplayInNewTabPage())
384 return true;
386 return false;
389 Extension::ManifestData* Extension::GetManifestData(const std::string& key)
390 const {
391 DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
392 ManifestDataMap::const_iterator iter = manifest_data_.find(key);
393 if (iter != manifest_data_.end())
394 return iter->second.get();
395 return NULL;
398 void Extension::SetManifestData(const std::string& key,
399 Extension::ManifestData* data) {
400 DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
401 manifest_data_[key] = linked_ptr<ManifestData>(data);
404 Manifest::Location Extension::location() const {
405 return manifest_->location();
408 const std::string& Extension::id() const {
409 return manifest_->extension_id();
412 const std::string Extension::VersionString() const {
413 return version()->GetString();
416 void Extension::AddInstallWarning(const InstallWarning& new_warning) {
417 install_warnings_.push_back(new_warning);
420 void Extension::AddInstallWarnings(
421 const std::vector<InstallWarning>& new_warnings) {
422 install_warnings_.insert(install_warnings_.end(),
423 new_warnings.begin(), new_warnings.end());
426 bool Extension::is_app() const {
427 return manifest_->is_app();
430 bool Extension::is_platform_app() const {
431 return manifest_->is_platform_app();
434 bool Extension::is_hosted_app() const {
435 return manifest()->is_hosted_app();
438 bool Extension::is_legacy_packaged_app() const {
439 return manifest()->is_legacy_packaged_app();
442 bool Extension::is_extension() const {
443 return manifest()->is_extension();
446 bool Extension::can_be_incognito_enabled() const {
447 // Only component platform apps are supported in incognito.
448 return !is_platform_app() || location() == Manifest::COMPONENT;
451 bool Extension::force_incognito_enabled() const {
452 return PermissionsData::HasAPIPermission(this, APIPermission::kProxy);
455 void Extension::AddWebExtentPattern(const URLPattern& pattern) {
456 extent_.AddPattern(pattern);
459 bool Extension::is_theme() const {
460 return manifest()->is_theme();
463 // static
464 bool Extension::InitExtensionID(extensions::Manifest* manifest,
465 const base::FilePath& path,
466 const std::string& explicit_id,
467 int creation_flags,
468 string16* error) {
469 if (!explicit_id.empty()) {
470 manifest->set_extension_id(explicit_id);
471 return true;
474 if (manifest->HasKey(keys::kPublicKey)) {
475 std::string public_key;
476 std::string public_key_bytes;
477 if (!manifest->GetString(keys::kPublicKey, &public_key) ||
478 !ParsePEMKeyBytes(public_key, &public_key_bytes)) {
479 *error = ASCIIToUTF16(errors::kInvalidKey);
480 return false;
482 std::string extension_id = id_util::GenerateId(public_key_bytes);
483 manifest->set_extension_id(extension_id);
484 return true;
487 if (creation_flags & REQUIRE_KEY) {
488 *error = ASCIIToUTF16(errors::kInvalidKey);
489 return false;
490 } else {
491 // If there is a path, we generate the ID from it. This is useful for
492 // development mode, because it keeps the ID stable across restarts and
493 // reloading the extension.
494 std::string extension_id = id_util::GenerateIdForPath(path);
495 if (extension_id.empty()) {
496 NOTREACHED() << "Could not create ID from path.";
497 return false;
499 manifest->set_extension_id(extension_id);
500 return true;
504 Extension::Extension(const base::FilePath& path,
505 scoped_ptr<extensions::Manifest> manifest)
506 : manifest_version_(0),
507 converted_from_user_script_(false),
508 manifest_(manifest.release()),
509 finished_parsing_manifest_(false),
510 display_in_launcher_(true),
511 display_in_new_tab_page_(true),
512 wants_file_access_(false),
513 creation_flags_(0) {
514 DCHECK(path.empty() || path.IsAbsolute());
515 path_ = id_util::MaybeNormalizePath(path);
518 Extension::~Extension() {
521 bool Extension::InitFromValue(int flags, string16* error) {
522 DCHECK(error);
524 creation_flags_ = flags;
526 // Important to load manifest version first because many other features
527 // depend on its value.
528 if (!LoadManifestVersion(error))
529 return false;
531 if (!LoadRequiredFeatures(error))
532 return false;
534 // We don't need to validate because InitExtensionID already did that.
535 manifest_->GetString(keys::kPublicKey, &public_key_);
537 extension_url_ = Extension::GetBaseURLFromExtensionId(id());
539 // Load App settings. LoadExtent at least has to be done before
540 // ParsePermissions(), because the valid permissions depend on what type of
541 // package this is.
542 if (is_app() && !LoadAppFeatures(error))
543 return false;
545 permissions_data_.reset(new PermissionsData);
546 if (!permissions_data_->ParsePermissions(this, error))
547 return false;
549 if (manifest_->HasKey(keys::kConvertedFromUserScript)) {
550 manifest_->GetBoolean(keys::kConvertedFromUserScript,
551 &converted_from_user_script_);
554 if (!LoadSharedFeatures(error))
555 return false;
557 finished_parsing_manifest_ = true;
559 permissions_data_->InitializeManifestPermissions(this);
560 permissions_data_->FinalizePermissions(this);
562 return true;
565 bool Extension::LoadRequiredFeatures(string16* error) {
566 if (!LoadName(error) ||
567 !LoadVersion(error))
568 return false;
569 return true;
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;
578 non_localized_name_ = UTF16ToUTF8(localized_name);
579 base::i18n::AdjustStringForLocaleDirection(&localized_name);
580 name_ = UTF16ToUTF8(localized_name);
581 return true;
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;
590 version_.reset(new Version(version_str));
591 if (!version_->IsValid() || version_->components().size() > 4) {
592 *error = ASCIIToUTF16(errors::kInvalidVersion);
593 return false;
595 return true;
598 bool Extension::LoadAppFeatures(string16* error) {
599 if (!LoadExtent(keys::kWebURLs, &extent_,
600 errors::kInvalidWebURLs, errors::kInvalidWebURL, error)) {
601 return false;
603 if (manifest_->HasKey(keys::kDisplayInLauncher) &&
604 !manifest_->GetBoolean(keys::kDisplayInLauncher, &display_in_launcher_)) {
605 *error = ASCIIToUTF16(errors::kInvalidDisplayInLauncher);
606 return false;
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;
614 } else {
615 // Inherit default from display_in_launcher property.
616 display_in_new_tab_page_ = display_in_launcher_;
618 return true;
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;
630 const base::ListValue* pattern_list = NULL;
631 if (!temp_pattern_value->GetAsList(&pattern_list)) {
632 *error = ASCIIToUTF16(list_error);
633 return false;
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;
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);
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;
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;
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;
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;
687 pattern.SetPath(pattern.path() + '*');
689 extent->AddPattern(pattern);
692 return true;
695 bool Extension::LoadSharedFeatures(string16* error) {
696 if (!LoadDescription(error) ||
697 !ManifestHandler::ParseExtension(this, error) ||
698 !LoadShortName(error))
699 return false;
701 return true;
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;
710 return true;
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;
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;
738 return true;
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;
750 base::i18n::AdjustStringForLocaleDirection(&localized_short_name);
751 short_name_ = UTF16ToUTF8(localized_short_name);
752 } else {
753 short_name_ = name_;
755 return true;
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());
769 ExtensionInfo::~ExtensionInfo() {}
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) {}
779 UnloadedExtensionInfo::UnloadedExtensionInfo(
780 const Extension* extension,
781 UnloadedExtensionInfo::Reason reason)
782 : reason(reason),
783 extension(extension) {}
785 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
786 const Extension* extension,
787 const PermissionSet* permissions,
788 Reason reason)
789 : reason(reason),
790 extension(extension),
791 permissions(permissions) {}
793 } // namespace extensions