Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: chrome/common/extensions/extension.cc

Issue 11280296: Refactor extension.cc to match ordering of extension.h. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: // static added to some missing members. Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/extension.h" 5 #include "chrome/common/extensions/extension.h"
6 6
7 #include <ostream> 7 #include <ostream>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 *target = 0; 274 *target = 0;
275 *error = ErrorUtils::FormatErrorMessageUTF16( 275 *error = ErrorUtils::FormatErrorMessageUTF16(
276 errors::kInvalidLaunchValue, 276 errors::kInvalidLaunchValue,
277 key); 277 key);
278 return false; 278 return false;
279 } 279 }
280 } 280 }
281 return true; 281 return true;
282 } 282 }
283 283
284 std::string SizeToString(const gfx::Size& max_size) {
285 return base::IntToString(max_size.width()) + "x" +
286 base::IntToString(max_size.height());
287 }
288
284 } // namespace 289 } // namespace
285 290
286 const FilePath::CharType Extension::kManifestFilename[] = 291 const FilePath::CharType Extension::kManifestFilename[] =
287 FILE_PATH_LITERAL("manifest.json"); 292 FILE_PATH_LITERAL("manifest.json");
288 const FilePath::CharType Extension::kLocaleFolder[] = 293 const FilePath::CharType Extension::kLocaleFolder[] =
289 FILE_PATH_LITERAL("_locales"); 294 FILE_PATH_LITERAL("_locales");
290 const FilePath::CharType Extension::kMessagesFilename[] = 295 const FilePath::CharType Extension::kMessagesFilename[] =
291 FILE_PATH_LITERAL("messages.json"); 296 FILE_PATH_LITERAL("messages.json");
292 297
293 #if defined(OS_WIN) 298 #if defined(OS_WIN)
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 Extension::ActionInfo::ActionInfo() {} 340 Extension::ActionInfo::ActionInfo() {}
336 Extension::ActionInfo::~ActionInfo() {} 341 Extension::ActionInfo::~ActionInfo() {}
337 342
338 Extension::FileHandlerInfo::FileHandlerInfo() {} 343 Extension::FileHandlerInfo::FileHandlerInfo() {}
339 Extension::FileHandlerInfo::~FileHandlerInfo() {} 344 Extension::FileHandlerInfo::~FileHandlerInfo() {}
340 345
341 // 346 //
342 // Extension 347 // Extension
343 // 348 //
344 349
350 bool Extension::InstallWarning::operator==(const InstallWarning& other) const {
351 return format == other.format && message == other.message;
352 }
353
345 // static 354 // static
346 scoped_refptr<Extension> Extension::Create(const FilePath& path, 355 scoped_refptr<Extension> Extension::Create(const FilePath& path,
347 Location location, 356 Location location,
348 const DictionaryValue& value, 357 const DictionaryValue& value,
349 int flags, 358 int flags,
350 std::string* utf8_error) { 359 std::string* utf8_error) {
351 return Extension::Create(path, 360 return Extension::Create(path,
352 location, 361 location,
353 value, 362 value,
354 flags, 363 flags,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 int loc2_rank = GetLocationRank(loc2); 413 int loc2_rank = GetLocationRank(loc2);
405 414
406 // If two different locations have the same rank, then we can not 415 // If two different locations have the same rank, then we can not
407 // deterministicly choose a location. 416 // deterministicly choose a location.
408 CHECK(loc1_rank != loc2_rank); 417 CHECK(loc1_rank != loc2_rank);
409 418
410 // Highest rank has highest priority. 419 // Highest rank has highest priority.
411 return (loc1_rank > loc2_rank ? loc1 : loc2 ); 420 return (loc1_rank > loc2_rank ? loc1 : loc2 );
412 } 421 }
413 422
414 void Extension::OverrideLaunchUrl(const GURL& override_url) {
415 GURL new_url(override_url);
416 if (!new_url.is_valid()) {
417 DLOG(WARNING) << "Invalid override url given for " << name();
418 } else {
419 if (new_url.has_port()) {
420 DLOG(WARNING) << "Override URL passed for " << name()
421 << " should not contain a port. Removing it.";
422
423 GURL::Replacements remove_port;
424 remove_port.ClearPort();
425 new_url = new_url.ReplaceComponents(remove_port);
426 }
427
428 launch_web_url_ = new_url.spec();
429
430 URLPattern pattern(kValidWebExtentSchemes);
431 URLPattern::ParseResult result = pattern.Parse(new_url.spec());
432 DCHECK_EQ(result, URLPattern::PARSE_SUCCESS);
433 pattern.SetPath(pattern.path() + '*');
434 extent_.AddPattern(pattern);
435 }
436 }
437
438 FilePath Extension::MaybeNormalizePath(const FilePath& path) {
439 #if defined(OS_WIN)
440 // Normalize any drive letter to upper-case. We do this for consistency with
441 // net_utils::FilePathToFileURL(), which does the same thing, to make string
442 // comparisons simpler.
443 std::wstring path_str = path.value();
444 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
445 path_str[1] == ':')
446 path_str[0] += ('A' - 'a');
447
448 return FilePath(path_str);
449 #else
450 return path;
451 #endif
452 }
453
454 Extension::Location Extension::location() const {
455 return manifest_->location();
456 }
457
458 const std::string& Extension::id() const {
459 return manifest_->extension_id();
460 }
461
462 const std::string Extension::VersionString() const {
463 return version()->GetString();
464 }
465
466 void Extension::AddInstallWarnings(
467 const InstallWarningVector& new_warnings) {
468 install_warnings_.insert(install_warnings_.end(),
469 new_warnings.begin(), new_warnings.end());
470 }
471
472 // static
473 bool Extension::IsExtension(const FilePath& file_name) {
474 return file_name.MatchesExtension(chrome::kExtensionFileExtension);
475 }
476
477 // static 423 // static
478 bool Extension::IdIsValid(const std::string& id) { 424 bool Extension::IdIsValid(const std::string& id) {
479 // Verify that the id is legal. 425 // Verify that the id is legal.
480 if (id.size() != (kIdSize * 2)) 426 if (id.size() != (kIdSize * 2))
481 return false; 427 return false;
482 428
483 // We only support lowercase IDs, because IDs can be used as URL components 429 // We only support lowercase IDs, because IDs can be used as URL components
484 // (where GURL will lowercase it). 430 // (where GURL will lowercase it).
485 std::string temp = StringToLowerASCII(id); 431 std::string temp = StringToLowerASCII(id);
486 for (size_t i = 0; i < temp.size(); i++) 432 for (size_t i = 0; i < temp.size(); i++)
487 if (temp[i] < 'a' || temp[i] > 'p') 433 if (temp[i] < 'a' || temp[i] > 'p')
488 return false; 434 return false;
489 435
490 return true; 436 return true;
491 } 437 }
492 438
493 // static 439 // static
494 std::string Extension::GenerateIdForPath(const FilePath& path) { 440 std::string Extension::GenerateIdForPath(const FilePath& path) {
495 FilePath new_path = Extension::MaybeNormalizePath(path); 441 FilePath new_path = Extension::MaybeNormalizePath(path);
496 std::string path_bytes = 442 std::string path_bytes =
497 std::string(reinterpret_cast<const char*>(new_path.value().data()), 443 std::string(reinterpret_cast<const char*>(new_path.value().data()),
498 new_path.value().size() * sizeof(FilePath::CharType)); 444 new_path.value().size() * sizeof(FilePath::CharType));
499 std::string id; 445 std::string id;
500 return GenerateId(path_bytes, &id) ? id : ""; 446 return GenerateId(path_bytes, &id) ? id : "";
501 } 447 }
502 448
449 // static
450 bool Extension::IsExtension(const FilePath& file_name) {
451 return file_name.MatchesExtension(chrome::kExtensionFileExtension);
452 }
453
503 void Extension::GetBasicInfo(bool enabled, 454 void Extension::GetBasicInfo(bool enabled,
504 DictionaryValue* info) const { 455 DictionaryValue* info) const {
505 info->SetString(info_keys::kIdKey, id()); 456 info->SetString(info_keys::kIdKey, id());
506 info->SetString(info_keys::kNameKey, name()); 457 info->SetString(info_keys::kNameKey, name());
507 info->SetBoolean(info_keys::kEnabledKey, enabled); 458 info->SetBoolean(info_keys::kEnabledKey, enabled);
508 info->SetBoolean(info_keys::kOfflineEnabledKey, offline_enabled()); 459 info->SetBoolean(info_keys::kOfflineEnabledKey, offline_enabled());
509 info->SetString(info_keys::kVersionKey, VersionString()); 460 info->SetString(info_keys::kVersionKey, VersionString());
510 info->SetString(info_keys::kDescriptionKey, description()); 461 info->SetString(info_keys::kDescriptionKey, description());
511 info->SetString(info_keys::kOptionsUrlKey, 462 info->SetString(info_keys::kOptionsUrlKey,
512 options_url().possibly_invalid_spec()); 463 options_url().possibly_invalid_spec());
(...skipping 21 matching lines...) Expand all
534 // to that base directory, so strip the leading "/" if present. 485 // to that base directory, so strip the leading "/" if present.
535 if (relative_path.size() > 0 && relative_path[0] == '/') 486 if (relative_path.size() > 0 && relative_path[0] == '/')
536 path = relative_path.substr(1); 487 path = relative_path.substr(1);
537 488
538 GURL ret_val = GURL(extension_url.spec() + path); 489 GURL ret_val = GURL(extension_url.spec() + path);
539 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false)); 490 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
540 491
541 return ret_val; 492 return ret_val;
542 } 493 }
543 494
544 bool Extension::is_platform_app() const {
545 return manifest_->is_platform_app();
546 }
547
548 bool Extension::is_hosted_app() const {
549 return manifest()->is_hosted_app();
550 }
551
552 bool Extension::is_legacy_packaged_app() const {
553 return manifest()->is_legacy_packaged_app();
554 }
555
556 bool Extension::is_theme() const {
557 return manifest()->is_theme();
558 }
559
560 GURL Extension::GetBackgroundURL() const {
561 if (background_scripts_.empty())
562 return background_url_;
563 return GetResourceURL(extension_filenames::kGeneratedBackgroundPageFilename);
564 }
565
566 bool Extension::ResourceMatches(const URLPatternSet& pattern_set, 495 bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
567 const std::string& resource) const { 496 const std::string& resource) const {
568 return pattern_set.MatchesURL(extension_url_.Resolve(resource)); 497 return pattern_set.MatchesURL(extension_url_.Resolve(resource));
569 } 498 }
570 499
571 bool Extension::IsResourceWebAccessible(const std::string& relative_path) 500 bool Extension::IsResourceWebAccessible(const std::string& relative_path)
572 const { 501 const {
573 // For old manifest versions which do not specify web_accessible_resources 502 // For old manifest versions which do not specify web_accessible_resources
574 // we always allow resource loads. 503 // we always allow resource loads.
575 if (manifest_version_ < 2 && !HasWebAccessibleResources()) 504 if (manifest_version_ < 2 && !HasWebAccessibleResources())
576 return true; 505 return true;
577 506
578 return ResourceMatches(web_accessible_resources_, relative_path); 507 return ResourceMatches(web_accessible_resources_, relative_path);
579 } 508 }
580 509
581 bool Extension::HasWebAccessibleResources() const {
582 return web_accessible_resources_.size() > 0;
583 }
584
585 bool Extension::IsSandboxedPage(const std::string& relative_path) const { 510 bool Extension::IsSandboxedPage(const std::string& relative_path) const {
586 return ResourceMatches(sandboxed_pages_, relative_path); 511 return ResourceMatches(sandboxed_pages_, relative_path);
587 } 512 }
588 513
589 std::string Extension::GetResourceContentSecurityPolicy( 514 std::string Extension::GetResourceContentSecurityPolicy(
590 const std::string& relative_path) const { 515 const std::string& relative_path) const {
591 return IsSandboxedPage(relative_path) ? 516 return IsSandboxedPage(relative_path) ?
592 sandboxed_pages_content_security_policy_ : content_security_policy(); 517 sandboxed_pages_content_security_policy_ : content_security_policy();
593 } 518 }
594 519
520 bool Extension::HasWebAccessibleResources() const {
521 return web_accessible_resources_.size() > 0;
522 }
523
524 ExtensionResource Extension::GetResource(
525 const std::string& relative_path) const {
526 std::string new_path = relative_path;
527 // We have some legacy data where resources have leading slashes.
528 // See: http://crbug.com/121164
529 if (!new_path.empty() && new_path.at(0) == '/')
530 new_path.erase(0, 1);
531 #if defined(OS_POSIX)
532 FilePath relative_file_path(new_path);
533 #elif defined(OS_WIN)
534 FilePath relative_file_path(UTF8ToWide(new_path));
535 #endif
536 ExtensionResource r(id(), path(), relative_file_path);
537 if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
538 r.set_follow_symlinks_anywhere();
539 }
540 return r;
541 }
542
543 ExtensionResource Extension::GetResource(
544 const FilePath& relative_file_path) const {
545 ExtensionResource r(id(), path(), relative_file_path);
546 if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
547 r.set_follow_symlinks_anywhere();
548 }
549 return r;
550 }
551
552 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
553 // util class in base:
554 // http://code.google.com/p/chromium/issues/detail?id=13572
555 // static
556 bool Extension::ParsePEMKeyBytes(const std::string& input,
557 std::string* output) {
558 DCHECK(output);
559 if (!output)
560 return false;
561 if (input.length() == 0)
562 return false;
563
564 std::string working = input;
565 if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
566 working = CollapseWhitespaceASCII(working, true);
567 size_t header_pos = working.find(kKeyInfoEndMarker,
568 sizeof(kKeyBeginHeaderMarker) - 1);
569 if (header_pos == std::string::npos)
570 return false;
571 size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
572 size_t end_pos = working.rfind(kKeyBeginFooterMarker);
573 if (end_pos == std::string::npos)
574 return false;
575 if (start_pos >= end_pos)
576 return false;
577
578 working = working.substr(start_pos, end_pos - start_pos);
579 if (working.length() == 0)
580 return false;
581 }
582
583 return base::Base64Decode(working, output);
584 }
585
586 // static
587 bool Extension::ProducePEM(const std::string& input, std::string* output) {
588 DCHECK(output);
589 return (input.length() == 0) ? false : base::Base64Encode(input, output);
590 }
591
592 // static
595 bool Extension::GenerateId(const std::string& input, std::string* output) { 593 bool Extension::GenerateId(const std::string& input, std::string* output) {
596 DCHECK(output); 594 DCHECK(output);
597 uint8 hash[Extension::kIdSize]; 595 uint8 hash[Extension::kIdSize];
598 crypto::SHA256HashString(input, hash, sizeof(hash)); 596 crypto::SHA256HashString(input, hash, sizeof(hash));
599 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash))); 597 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash)));
600 ConvertHexadecimalToIDAlphabet(output); 598 ConvertHexadecimalToIDAlphabet(output);
601 599
602 return true; 600 return true;
603 } 601 }
604 602
605 // Helper method that loads a UserScript object from a dictionary in the 603 // static
606 // content_script list of the manifest. 604 bool Extension::FormatPEMForFileOutput(const std::string& input,
607 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, 605 std::string* output,
608 int definition_index, 606 bool is_public) {
609 string16* error, 607 DCHECK(output);
610 UserScript* result) { 608 if (input.length() == 0)
611 // run_at 609 return false;
612 if (content_script->HasKey(keys::kRunAt)) { 610 *output = "";
613 std::string run_location; 611 output->append(kKeyBeginHeaderMarker);
614 if (!content_script->GetString(keys::kRunAt, &run_location)) { 612 output->append(" ");
613 output->append(is_public ? kPublic : kPrivate);
614 output->append(" ");
615 output->append(kKeyInfoEndMarker);
616 output->append("\n");
617 for (size_t i = 0; i < input.length(); ) {
618 int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
619 output->append(input.substr(i, slice));
620 output->append("\n");
621 i += slice;
622 }
623 output->append(kKeyBeginFooterMarker);
624 output->append(" ");
625 output->append(is_public ? kPublic : kPrivate);
626 output->append(" ");
627 output->append(kKeyInfoEndMarker);
628 output->append("\n");
629
630 return true;
631 }
632
633 // static
634 void Extension::DecodeIcon(const Extension* extension,
635 int preferred_icon_size,
636 ExtensionIconSet::MatchType match_type,
637 scoped_ptr<SkBitmap>* result) {
638 std::string path = extension->icons().Get(preferred_icon_size, match_type);
639 int size = extension->icons().GetIconSizeFromPath(path);
640 ExtensionResource icon_resource = extension->GetResource(path);
641 DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
642 }
643
644 // static
645 void Extension::DecodeIcon(const Extension* extension,
646 int icon_size,
647 scoped_ptr<SkBitmap>* result) {
648 DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
649 }
650
651 // static
652 void Extension::DecodeIconFromPath(const FilePath& icon_path,
653 int icon_size,
654 scoped_ptr<SkBitmap>* result) {
655 if (icon_path.empty())
656 return;
657
658 std::string file_contents;
659 if (!file_util::ReadFileToString(icon_path, &file_contents)) {
660 DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
661 return;
662 }
663
664 // Decode the image using WebKit's image decoder.
665 const unsigned char* data =
666 reinterpret_cast<const unsigned char*>(file_contents.data());
667 webkit_glue::ImageDecoder decoder;
668 scoped_ptr<SkBitmap> decoded(new SkBitmap());
669 *decoded = decoder.Decode(data, file_contents.length());
670 if (decoded->empty()) {
671 DLOG(ERROR) << "Could not decode icon file: "
672 << icon_path.LossyDisplayName();
673 return;
674 }
675
676 if (decoded->width() != icon_size || decoded->height() != icon_size) {
677 DLOG(ERROR) << "Icon file has unexpected size: "
678 << base::IntToString(decoded->width()) << "x"
679 << base::IntToString(decoded->height());
680 return;
681 }
682
683 result->swap(decoded);
684 }
685
686 // static
687 const gfx::ImageSkia& Extension::GetDefaultIcon(bool is_app) {
688 int id = is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON;
689 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
690 }
691
692 // static
693 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
694 return GURL(std::string(extensions::kExtensionScheme) +
695 content::kStandardSchemeSeparator + extension_id + "/");
696 }
697
698 // static
699 void Extension::SetScriptingWhitelist(
700 const Extension::ScriptingWhitelist& whitelist) {
701 ScriptingWhitelist* current_whitelist =
702 ExtensionConfig::GetInstance()->whitelist();
703 current_whitelist->clear();
704 for (ScriptingWhitelist::const_iterator it = whitelist.begin();
705 it != whitelist.end(); ++it) {
706 current_whitelist->push_back(*it);
707 }
708 }
709
710 // static
711 const Extension::ScriptingWhitelist* Extension::GetScriptingWhitelist() {
712 return ExtensionConfig::GetInstance()->whitelist();
713 }
714
715 bool Extension::ParsePermissions(const char* key,
716 string16* error,
717 APIPermissionSet* api_permissions,
718 URLPatternSet* host_permissions) {
719 if (manifest_->HasKey(key)) {
720 ListValue* permissions = NULL;
721 if (!manifest_->GetList(key, &permissions)) {
615 *error = ErrorUtils::FormatErrorMessageUTF16( 722 *error = ErrorUtils::FormatErrorMessageUTF16(
616 errors::kInvalidRunAt, 723 errors::kInvalidPermissions, "");
617 base::IntToString(definition_index)); 724 return false;
618 return false; 725 }
619 } 726
620 727 // NOTE: We need to get the APIPermission before we check if features
621 if (run_location == values::kRunAtDocumentStart) { 728 // associated with them are available because the feature system does not
622 result->set_run_location(UserScript::DOCUMENT_START); 729 // know about aliases.
623 } else if (run_location == values::kRunAtDocumentEnd) { 730
624 result->set_run_location(UserScript::DOCUMENT_END); 731 std::vector<std::string> host_data;
625 } else if (run_location == values::kRunAtDocumentIdle) { 732 if (!APIPermissionSet::ParseFromJSON(permissions, api_permissions,
626 result->set_run_location(UserScript::DOCUMENT_IDLE); 733 error, &host_data))
627 } else { 734 return false;
628 *error = ErrorUtils::FormatErrorMessageUTF16( 735
629 errors::kInvalidRunAt, 736 // Verify feature availability of permissions.
630 base::IntToString(definition_index)); 737 std::vector<APIPermission::ID> to_remove;
631 return false; 738 SimpleFeatureProvider* permission_features =
632 } 739 SimpleFeatureProvider::GetPermissionFeatures();
633 } 740 for (APIPermissionSet::const_iterator it = api_permissions->begin();
634 741 it != api_permissions->end(); ++it) {
635 // all frames 742 extensions::Feature* feature =
636 if (content_script->HasKey(keys::kAllFrames)) { 743 permission_features->GetFeature(it->name());
637 bool all_frames = false; 744
638 if (!content_script->GetBoolean(keys::kAllFrames, &all_frames)) { 745 // The feature should exist since we just got an APIPermission
639 *error = ErrorUtils::FormatErrorMessageUTF16( 746 // for it. The two systems should be updated together whenever a
640 errors::kInvalidAllFrames, base::IntToString(definition_index)); 747 // permission is added.
641 return false; 748 CHECK(feature);
642 } 749
643 result->set_match_all_frames(all_frames); 750 Feature::Availability availability =
644 } 751 feature->IsAvailableToManifest(
645 752 id(),
646 // matches (required) 753 GetType(),
647 const ListValue* matches = NULL; 754 Feature::ConvertLocation(location()),
648 if (!content_script->GetList(keys::kMatches, &matches)) { 755 manifest_version());
649 *error = ErrorUtils::FormatErrorMessageUTF16( 756 if (!availability.is_available()) {
650 errors::kInvalidMatches, 757 // Don't fail, but warn the developer that the manifest contains
651 base::IntToString(definition_index)); 758 // unrecognized permissions. This may happen legitimately if the
652 return false; 759 // extensions requests platform- or channel-specific permissions.
653 } 760 install_warnings_.push_back(InstallWarning(InstallWarning::FORMAT_TEXT,
654 761 availability.message()));
655 if (matches->GetSize() == 0) { 762 to_remove.push_back(it->id());
656 *error = ErrorUtils::FormatErrorMessageUTF16( 763 continue;
657 errors::kInvalidMatchCount, 764 }
658 base::IntToString(definition_index)); 765
659 return false; 766 if (it->id() == APIPermission::kExperimental) {
660 } 767 if (!CanSpecifyExperimentalPermission()) {
661 for (size_t j = 0; j < matches->GetSize(); ++j) { 768 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
662 std::string match_str; 769 return false;
663 if (!matches->GetString(j, &match_str)) {
664 *error = ErrorUtils::FormatErrorMessageUTF16(
665 errors::kInvalidMatch,
666 base::IntToString(definition_index),
667 base::IntToString(j),
668 errors::kExpectString);
669 return false;
670 }
671
672 URLPattern pattern(UserScript::kValidUserScriptSchemes);
673 if (CanExecuteScriptEverywhere())
674 pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
675
676 URLPattern::ParseResult parse_result = pattern.Parse(match_str);
677 if (parse_result != URLPattern::PARSE_SUCCESS) {
678 *error = ErrorUtils::FormatErrorMessageUTF16(
679 errors::kInvalidMatch,
680 base::IntToString(definition_index),
681 base::IntToString(j),
682 URLPattern::GetParseResultString(parse_result));
683 return false;
684 }
685
686 if (pattern.MatchesScheme(chrome::kFileScheme) &&
687 !CanExecuteScriptEverywhere()) {
688 wants_file_access_ = true;
689 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
690 pattern.SetValidSchemes(
691 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
692 }
693 }
694
695 result->add_url_pattern(pattern);
696 }
697
698 // exclude_matches
699 if (content_script->HasKey(keys::kExcludeMatches)) { // optional
700 const ListValue* exclude_matches = NULL;
701 if (!content_script->GetList(keys::kExcludeMatches, &exclude_matches)) {
702 *error = ErrorUtils::FormatErrorMessageUTF16(
703 errors::kInvalidExcludeMatches,
704 base::IntToString(definition_index));
705 return false;
706 }
707
708 for (size_t j = 0; j < exclude_matches->GetSize(); ++j) {
709 std::string match_str;
710 if (!exclude_matches->GetString(j, &match_str)) {
711 *error = ErrorUtils::FormatErrorMessageUTF16(
712 errors::kInvalidExcludeMatch,
713 base::IntToString(definition_index),
714 base::IntToString(j),
715 errors::kExpectString);
716 return false;
717 }
718
719 URLPattern pattern(UserScript::kValidUserScriptSchemes);
720 if (CanExecuteScriptEverywhere())
721 pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
722 URLPattern::ParseResult parse_result = pattern.Parse(match_str);
723 if (parse_result != URLPattern::PARSE_SUCCESS) {
724 *error = ErrorUtils::FormatErrorMessageUTF16(
725 errors::kInvalidExcludeMatch,
726 base::IntToString(definition_index), base::IntToString(j),
727 URLPattern::GetParseResultString(parse_result));
728 return false;
729 }
730
731 result->add_exclude_url_pattern(pattern);
732 }
733 }
734
735 // include/exclude globs (mostly for Greasemonkey compatibility)
736 if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
737 error, &UserScript::add_glob, result)) {
738 return false;
739 }
740
741 if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
742 error, &UserScript::add_exclude_glob, result)) {
743 return false;
744 }
745
746 // js and css keys
747 const ListValue* js = NULL;
748 if (content_script->HasKey(keys::kJs) &&
749 !content_script->GetList(keys::kJs, &js)) {
750 *error = ErrorUtils::FormatErrorMessageUTF16(
751 errors::kInvalidJsList,
752 base::IntToString(definition_index));
753 return false;
754 }
755
756 const ListValue* css = NULL;
757 if (content_script->HasKey(keys::kCss) &&
758 !content_script->GetList(keys::kCss, &css)) {
759 *error = ErrorUtils::
760 FormatErrorMessageUTF16(errors::kInvalidCssList,
761 base::IntToString(definition_index));
762 return false;
763 }
764
765 // The manifest needs to have at least one js or css user script definition.
766 if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
767 *error = ErrorUtils::FormatErrorMessageUTF16(
768 errors::kMissingFile,
769 base::IntToString(definition_index));
770 return false;
771 }
772
773 if (js) {
774 for (size_t script_index = 0; script_index < js->GetSize();
775 ++script_index) {
776 const Value* value;
777 std::string relative;
778 if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
779 *error = ErrorUtils::FormatErrorMessageUTF16(
780 errors::kInvalidJs,
781 base::IntToString(definition_index),
782 base::IntToString(script_index));
783 return false;
784 }
785 GURL url = GetResourceURL(relative);
786 ExtensionResource resource = GetResource(relative);
787 result->js_scripts().push_back(UserScript::File(
788 resource.extension_root(), resource.relative_path(), url));
789 }
790 }
791
792 if (css) {
793 for (size_t script_index = 0; script_index < css->GetSize();
794 ++script_index) {
795 const Value* value;
796 std::string relative;
797 if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
798 *error = ErrorUtils::FormatErrorMessageUTF16(
799 errors::kInvalidCss,
800 base::IntToString(definition_index),
801 base::IntToString(script_index));
802 return false;
803 }
804 GURL url = GetResourceURL(relative);
805 ExtensionResource resource = GetResource(relative);
806 result->css_scripts().push_back(UserScript::File(
807 resource.extension_root(), resource.relative_path(), url));
808 }
809 }
810
811 return true;
812 }
813
814 bool Extension::LoadGlobsHelper(
815 const DictionaryValue* content_script,
816 int content_script_index,
817 const char* globs_property_name,
818 string16* error,
819 void(UserScript::*add_method)(const std::string& glob),
820 UserScript* instance) {
821 if (!content_script->HasKey(globs_property_name))
822 return true; // they are optional
823
824 const ListValue* list = NULL;
825 if (!content_script->GetList(globs_property_name, &list)) {
826 *error = ErrorUtils::FormatErrorMessageUTF16(
827 errors::kInvalidGlobList,
828 base::IntToString(content_script_index),
829 globs_property_name);
830 return false;
831 }
832
833 for (size_t i = 0; i < list->GetSize(); ++i) {
834 std::string glob;
835 if (!list->GetString(i, &glob)) {
836 *error = ErrorUtils::FormatErrorMessageUTF16(
837 errors::kInvalidGlob,
838 base::IntToString(content_script_index),
839 globs_property_name,
840 base::IntToString(i));
841 return false;
842 }
843
844 (instance->*add_method)(glob);
845 }
846
847 return true;
848 }
849
850 scoped_ptr<Extension::ActionInfo> Extension::LoadExtensionActionInfoHelper(
851 const DictionaryValue* extension_action,
852 ActionInfo::Type action_type,
853 string16* error) {
854 scoped_ptr<ActionInfo> result(new ActionInfo());
855
856 if (manifest_version_ == 1) {
857 // kPageActionIcons is obsolete, and used by very few extensions. Continue
858 // loading it, but only take the first icon as the default_icon path.
859 const ListValue* icons = NULL;
860 if (extension_action->HasKey(keys::kPageActionIcons) &&
861 extension_action->GetList(keys::kPageActionIcons, &icons)) {
862 for (ListValue::const_iterator iter = icons->begin();
863 iter != icons->end(); ++iter) {
864 std::string path;
865 if (!(*iter)->GetAsString(&path) || !NormalizeAndValidatePath(&path)) {
866 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
867 return scoped_ptr<ActionInfo>();
868 } 770 }
869 771 }
870 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path); 772 }
871 break; 773
872 } 774 // Remove permissions that are not available to this extension.
873 } 775 for (std::vector<APIPermission::ID>::const_iterator it = to_remove.begin();
874 776 it != to_remove.end(); ++it) {
875 std::string id; 777 api_permissions->erase(*it);
876 if (extension_action->HasKey(keys::kPageActionId)) { 778 }
877 if (!extension_action->GetString(keys::kPageActionId, &id)) { 779
878 *error = ASCIIToUTF16(errors::kInvalidPageActionId); 780 // Parse host pattern permissions.
879 return scoped_ptr<ActionInfo>(); 781 const int kAllowedSchemes = CanExecuteScriptEverywhere() ?
880 } 782 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes;
881 result->id = id; 783
882 } 784 for (std::vector<std::string>::const_iterator it = host_data.begin();
883 } 785 it != host_data.end(); ++it) {
884 786 const std::string& permission_str = *it;
885 // Read the page action |default_icon| (optional). 787
886 // The |default_icon| value can be either dictionary {icon size -> icon path} 788 // Check if it's a host pattern permission.
887 // or non empty string value. 789 URLPattern pattern = URLPattern(kAllowedSchemes);
888 if (extension_action->HasKey(keys::kPageActionDefaultIcon)) { 790 URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
889 const DictionaryValue* icons_value = NULL; 791 if (parse_result == URLPattern::PARSE_SUCCESS) {
890 std::string default_icon; 792 if (!CanSpecifyHostPermission(pattern, *api_permissions)) {
891 if (extension_action->GetDictionary(keys::kPageActionDefaultIcon, 793 *error = ErrorUtils::FormatErrorMessageUTF16(
892 &icons_value)) { 794 errors::kInvalidPermissionScheme, permission_str);
893 if (!LoadIconsFromDictionary(icons_value, 795 return false;
894 extension_misc::kExtensionActionIconSizes, 796 }
895 extension_misc::kNumExtensionActionIconSizes, 797
896 &result->default_icon, 798 // The path component is not used for host permissions, so we force it
897 error)) { 799 // to match all paths.
898 return scoped_ptr<ActionInfo>(); 800 pattern.SetPath("/*");
899 } 801
900 } else if (extension_action->GetString(keys::kPageActionDefaultIcon, 802 if (pattern.MatchesScheme(chrome::kFileScheme) &&
901 &default_icon) && 803 !CanExecuteScriptEverywhere()) {
902 NormalizeAndValidatePath(&default_icon)) { 804 wants_file_access_ = true;
903 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, 805 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
904 default_icon); 806 pattern.SetValidSchemes(
905 } else { 807 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
906 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); 808 }
907 return scoped_ptr<ActionInfo>(); 809 }
908 } 810
909 } 811 host_permissions->AddPattern(pattern);
910 812 continue;
911 // Read the page action title from |default_title| if present, |name| if not 813 }
912 // (both optional). 814
913 if (extension_action->HasKey(keys::kPageActionDefaultTitle)) { 815 // It's probably an unknown API permission. Do not throw an error so
914 if (!extension_action->GetString(keys::kPageActionDefaultTitle, 816 // extensions can retain backwards compatability (http://crbug.com/42742).
915 &result->default_title)) { 817 install_warnings_.push_back(InstallWarning(
916 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); 818 InstallWarning::FORMAT_TEXT,
917 return scoped_ptr<ActionInfo>(); 819 base::StringPrintf(
918 } 820 "Permission '%s' is unknown or URL pattern is malformed.",
919 } else if (manifest_version_ == 1 && extension_action->HasKey(keys::kName)) { 821 permission_str.c_str())));
920 if (!extension_action->GetString(keys::kName, &result->default_title)) { 822 }
921 *error = ASCIIToUTF16(errors::kInvalidPageActionName); 823 }
922 return scoped_ptr<ActionInfo>(); 824 return true;
923 } 825 }
924 } 826
925 827 bool Extension::HasAPIPermission(APIPermission::ID permission) const {
926 // Read the action's |popup| (optional). 828 base::AutoLock auto_lock(runtime_data_lock_);
927 const char* popup_key = NULL; 829 return runtime_data_.GetActivePermissions()->HasAPIPermission(permission);
928 if (extension_action->HasKey(keys::kPageActionDefaultPopup)) 830 }
929 popup_key = keys::kPageActionDefaultPopup; 831
930 832 bool Extension::HasAPIPermission(const std::string& function_name) const {
931 if (manifest_version_ == 1 && 833 base::AutoLock auto_lock(runtime_data_lock_);
932 extension_action->HasKey(keys::kPageActionPopup)) { 834 return runtime_data_.GetActivePermissions()->
933 if (popup_key) { 835 HasAccessToFunction(function_name);
934 *error = ErrorUtils::FormatErrorMessageUTF16( 836 }
935 errors::kInvalidPageActionOldAndNewKeys, 837
936 keys::kPageActionDefaultPopup, 838 bool Extension::HasAPIPermissionForTab(int tab_id,
937 keys::kPageActionPopup); 839 APIPermission::ID permission) const {
938 return scoped_ptr<ActionInfo>(); 840 base::AutoLock auto_lock(runtime_data_lock_);
939 } 841 if (runtime_data_.GetActivePermissions()->HasAPIPermission(permission))
940 popup_key = keys::kPageActionPopup; 842 return true;
941 } 843 scoped_refptr<const PermissionSet> tab_specific_permissions =
942 844 runtime_data_.GetTabSpecificPermissions(tab_id);
943 if (popup_key) { 845 return tab_specific_permissions.get() &&
944 const DictionaryValue* popup = NULL; 846 tab_specific_permissions->HasAPIPermission(permission);
945 std::string url_str; 847 }
946 848
947 if (extension_action->GetString(popup_key, &url_str)) { 849 bool Extension::CheckAPIPermissionWithParam(APIPermission::ID permission,
948 // On success, |url_str| is set. Nothing else to do. 850 const APIPermission::CheckParam* param) const {
949 } else if (manifest_version_ == 1 && 851 base::AutoLock auto_lock(runtime_data_lock_);
950 extension_action->GetDictionary(popup_key, &popup)) { 852 return runtime_data_.GetActivePermissions()->
951 if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) { 853 CheckAPIPermissionWithParam(permission, param);
952 *error = ErrorUtils::FormatErrorMessageUTF16( 854 }
953 errors::kInvalidPageActionPopupPath, "<missing>"); 855
954 return scoped_ptr<ActionInfo>(); 856 const URLPatternSet& Extension::GetEffectiveHostPermissions() const {
955 } 857 base::AutoLock auto_lock(runtime_data_lock_);
956 } else { 858 return runtime_data_.GetActivePermissions()->effective_hosts();
957 *error = ASCIIToUTF16(errors::kInvalidPageActionPopup); 859 }
958 return scoped_ptr<ActionInfo>(); 860
959 } 861 bool Extension::CanSilentlyIncreasePermissions() const {
960 862 return location() != INTERNAL;
961 if (!url_str.empty()) { 863 }
962 // An empty string is treated as having no popup. 864
963 result->default_popup_url = GetResourceURL(url_str); 865 bool Extension::HasHostPermission(const GURL& url) const {
964 if (!result->default_popup_url.is_valid()) { 866 if (url.SchemeIs(chrome::kChromeUIScheme) &&
965 *error = ErrorUtils::FormatErrorMessageUTF16( 867 url.host() != chrome::kChromeUIFaviconHost &&
966 errors::kInvalidPageActionPopupPath, url_str); 868 url.host() != chrome::kChromeUIThumbnailHost &&
967 return scoped_ptr<ActionInfo>(); 869 location() != Extension::COMPONENT) {
968 } 870 return false;
969 } else { 871 }
970 DCHECK(result->default_popup_url.is_empty()) 872
971 << "Shouldn't be possible for the popup to be set."; 873 base::AutoLock auto_lock(runtime_data_lock_);
972 } 874 return runtime_data_.GetActivePermissions()->
973 } 875 HasExplicitAccessToOrigin(url);
974 876 }
975 return result.Pass(); 877
878 bool Extension::HasEffectiveAccessToAllHosts() const {
879 base::AutoLock auto_lock(runtime_data_lock_);
880 return runtime_data_.GetActivePermissions()->HasEffectiveAccessToAllHosts();
881 }
882
883 bool Extension::HasFullPermissions() const {
884 base::AutoLock auto_lock(runtime_data_lock_);
885 return runtime_data_.GetActivePermissions()->HasEffectiveFullAccess();
886 }
887
888 PermissionMessages Extension::GetPermissionMessages() const {
889 base::AutoLock auto_lock(runtime_data_lock_);
890 if (IsTrustedId(id())) {
891 return PermissionMessages();
892 } else {
893 return runtime_data_.GetActivePermissions()->GetPermissionMessages(
894 GetType());
895 }
896 }
897
898 std::vector<string16> Extension::GetPermissionMessageStrings() const {
899 base::AutoLock auto_lock(runtime_data_lock_);
900 if (IsTrustedId(id()))
901 return std::vector<string16>();
902 else
903 return runtime_data_.GetActivePermissions()->GetWarningMessages(GetType());
904 }
905
906 bool Extension::ShouldSkipPermissionWarnings() const {
907 return IsTrustedId(id());
908 }
909
910 void Extension::SetActivePermissions(
911 const PermissionSet* permissions) const {
912 base::AutoLock auto_lock(runtime_data_lock_);
913 runtime_data_.SetActivePermissions(permissions);
914 }
915
916 scoped_refptr<const PermissionSet>
917 Extension::GetActivePermissions() const {
918 base::AutoLock auto_lock(runtime_data_lock_);
919 return runtime_data_.GetActivePermissions();
920 }
921
922 bool Extension::ShowConfigureContextMenus() const {
923 // Don't show context menu for component extensions. We might want to show
924 // options for component extension button but now there is no component
925 // extension with options. All other menu items like uninstall have
926 // no sense for component extensions.
927 return location() != Extension::COMPONENT;
928 }
929
930 GURL Extension::GetHomepageURL() const {
931 if (homepage_url_.is_valid())
932 return homepage_url_;
933
934 return UpdatesFromGallery() ?
935 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id()) : GURL();
936 }
937
938 std::set<FilePath> Extension::GetBrowserImages() const {
939 std::set<FilePath> image_paths;
940 // TODO(viettrungluu): These |FilePath::FromWStringHack(UTF8ToWide())|
941 // indicate that we're doing something wrong.
942
943 // Extension icons.
944 for (ExtensionIconSet::IconMap::const_iterator iter = icons().map().begin();
945 iter != icons().map().end(); ++iter) {
946 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
947 }
948
949 // Theme images.
950 DictionaryValue* theme_images = GetThemeImages();
951 if (theme_images) {
952 for (DictionaryValue::key_iterator it = theme_images->begin_keys();
953 it != theme_images->end_keys(); ++it) {
954 std::string val;
955 if (theme_images->GetStringWithoutPathExpansion(*it, &val))
956 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(val)));
957 }
958 }
959
960 if (page_action_info() && !page_action_info()->default_icon.empty()) {
961 for (ExtensionIconSet::IconMap::const_iterator iter =
962 page_action_info()->default_icon.map().begin();
963 iter != page_action_info()->default_icon.map().end();
964 ++iter) {
965 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
966 }
967 }
968
969 if (browser_action_info() && !browser_action_info()->default_icon.empty()) {
970 for (ExtensionIconSet::IconMap::const_iterator iter =
971 browser_action_info()->default_icon.map().begin();
972 iter != browser_action_info()->default_icon.map().end();
973 ++iter) {
974 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
975 }
976 }
977
978 return image_paths;
979 }
980
981 ExtensionResource Extension::GetIconResource(
982 int size, ExtensionIconSet::MatchType match_type) const {
983 std::string path = icons().Get(size, match_type);
984 return path.empty() ? ExtensionResource() : GetResource(path);
985 }
986
987 GURL Extension::GetIconURL(int size,
988 ExtensionIconSet::MatchType match_type) const {
989 std::string path = icons().Get(size, match_type);
990 return path.empty() ? GURL() : GetResourceURL(path);
991 }
992
993 GURL Extension::GetFullLaunchURL() const {
994 return launch_local_path().empty() ? GURL(launch_web_url()) :
995 url().Resolve(launch_local_path());
996 }
997
998 void Extension::SetCachedImage(const ExtensionResource& source,
999 const SkBitmap& image,
1000 const gfx::Size& original_size) const {
1001 DCHECK(source.extension_root() == path()); // The resource must come from
1002 // this extension.
1003 const FilePath& path = source.relative_path();
1004 gfx::Size actual_size(image.width(), image.height());
1005 std::string location;
1006 if (actual_size != original_size)
1007 location = SizeToString(actual_size);
1008 image_cache_[ImageCacheKey(path, location)] = image;
1009 }
1010
1011 bool Extension::HasCachedImage(const ExtensionResource& source,
1012 const gfx::Size& max_size) const {
1013 DCHECK(source.extension_root() == path()); // The resource must come from
1014 // this extension.
1015 return GetCachedImageImpl(source, max_size) != NULL;
1016 }
1017
1018 SkBitmap Extension::GetCachedImage(const ExtensionResource& source,
1019 const gfx::Size& max_size) const {
1020 DCHECK(source.extension_root() == path()); // The resource must come from
1021 // this extension.
1022 SkBitmap* image = GetCachedImageImpl(source, max_size);
1023 return image ? *image : SkBitmap();
1024 }
1025
1026 bool Extension::CanExecuteScriptOnPage(const GURL& document_url,
1027 const GURL& top_frame_url,
1028 int tab_id,
1029 const UserScript* script,
1030 std::string* error) const {
1031 base::AutoLock auto_lock(runtime_data_lock_);
1032 // The gallery is special-cased as a restricted URL for scripting to prevent
1033 // access to special JS bindings we expose to the gallery (and avoid things
1034 // like extensions removing the "report abuse" link).
1035 // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
1036 // against the store app extent?
1037 GURL store_url(extension_urls::GetWebstoreLaunchURL());
1038 if ((document_url.host() == store_url.host()) &&
1039 !CanExecuteScriptEverywhere() &&
1040 !CommandLine::ForCurrentProcess()->HasSwitch(
1041 switches::kAllowScriptingGallery)) {
1042 if (error)
1043 *error = errors::kCannotScriptGallery;
1044 return false;
1045 }
1046
1047 if (document_url.SchemeIs(chrome::kChromeUIScheme) &&
1048 !CanExecuteScriptEverywhere()) {
1049 return false;
1050 }
1051
1052 if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
1053 top_frame_url.GetOrigin() !=
1054 GetBaseURLFromExtensionId(id()).GetOrigin() &&
1055 !CanExecuteScriptEverywhere()) {
1056 return false;
1057 }
1058
1059 // If a tab ID is specified, try the tab-specific permissions.
1060 if (tab_id >= 0) {
1061 scoped_refptr<const PermissionSet> tab_permissions =
1062 runtime_data_.GetTabSpecificPermissions(tab_id);
1063 if (tab_permissions.get() &&
1064 tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
1065 return true;
1066 }
1067 }
1068
1069 // If a script is specified, use its matches.
1070 if (script)
1071 return script->MatchesURL(document_url);
1072
1073 // Otherwise, see if this extension has permission to execute script
1074 // programmatically on pages.
1075 if (runtime_data_.GetActivePermissions()->HasExplicitAccessToOrigin(
1076 document_url)) {
1077 return true;
1078 }
1079
1080 if (error) {
1081 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
1082 document_url.spec());
1083 }
1084
1085 return false;
1086 }
1087
1088 bool Extension::CanExecuteScriptEverywhere() const {
1089 if (location() == Extension::COMPONENT)
1090 return true;
1091
1092 ScriptingWhitelist* whitelist = ExtensionConfig::GetInstance()->whitelist();
1093
1094 for (ScriptingWhitelist::const_iterator it = whitelist->begin();
1095 it != whitelist->end(); ++it) {
1096 if (id() == *it) {
1097 return true;
1098 }
1099 }
1100
1101 return false;
1102 }
1103
1104 bool Extension::CanCaptureVisiblePage(const GURL& page_url,
1105 int tab_id,
1106 std::string* error) const {
1107 if (tab_id >= 0) {
1108 scoped_refptr<const PermissionSet> tab_permissions =
1109 GetTabSpecificPermissions(tab_id);
1110 if (tab_permissions.get() &&
1111 tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) {
1112 return true;
1113 }
1114 }
1115
1116 if (HasHostPermission(page_url) || page_url.GetOrigin() == url())
1117 return true;
1118
1119 if (error) {
1120 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
1121 page_url.spec());
1122 }
1123 return false;
1124 }
1125
1126 bool Extension::UpdatesFromGallery() const {
1127 return extension_urls::IsWebstoreUpdateUrl(update_url());
1128 }
1129
1130 bool Extension::OverlapsWithOrigin(const GURL& origin) const {
1131 if (url() == origin)
1132 return true;
1133
1134 if (web_extent().is_empty())
1135 return false;
1136
1137 // Note: patterns and extents ignore port numbers.
1138 URLPattern origin_only_pattern(kValidWebExtentSchemes);
1139 if (!origin_only_pattern.SetScheme(origin.scheme()))
1140 return false;
1141 origin_only_pattern.SetHost(origin.host());
1142 origin_only_pattern.SetPath("/*");
1143
1144 URLPatternSet origin_only_pattern_list;
1145 origin_only_pattern_list.AddPattern(origin_only_pattern);
1146
1147 return web_extent().OverlapsWith(origin_only_pattern_list);
1148 }
1149
1150 Extension::SyncType Extension::GetSyncType() const {
1151 if (!IsSyncable()) {
1152 // We have a non-standard location.
1153 return SYNC_TYPE_NONE;
1154 }
1155
1156 // Disallow extensions with non-gallery auto-update URLs for now.
1157 //
1158 // TODO(akalin): Relax this restriction once we've put in UI to
1159 // approve synced extensions.
1160 if (!update_url().is_empty() && !UpdatesFromGallery())
1161 return SYNC_TYPE_NONE;
1162
1163 // Disallow extensions with native code plugins.
1164 //
1165 // TODO(akalin): Relax this restriction once we've put in UI to
1166 // approve synced extensions.
1167 if (!plugins().empty()) {
1168 return SYNC_TYPE_NONE;
1169 }
1170
1171 switch (GetType()) {
1172 case Extension::TYPE_EXTENSION:
1173 return SYNC_TYPE_EXTENSION;
1174
1175 case Extension::TYPE_USER_SCRIPT:
1176 // We only want to sync user scripts with gallery update URLs.
1177 if (UpdatesFromGallery())
1178 return SYNC_TYPE_EXTENSION;
1179 else
1180 return SYNC_TYPE_NONE;
1181
1182 case Extension::TYPE_HOSTED_APP:
1183 case Extension::TYPE_LEGACY_PACKAGED_APP:
1184 case Extension::TYPE_PLATFORM_APP:
1185 return SYNC_TYPE_APP;
1186
1187 default:
1188 return SYNC_TYPE_NONE;
1189 }
1190 }
1191
1192 bool Extension::IsSyncable() const {
1193 // TODO(akalin): Figure out if we need to allow some other types.
1194
1195 // Default apps are not synced because otherwise they will pollute profiles
1196 // that don't already have them. Specially, if a user doesn't have default
1197 // apps, creates a new profile (which get default apps) and then enables sync
1198 // for it, then their profile everywhere gets the default apps.
1199 bool is_syncable = (location() == Extension::INTERNAL &&
1200 !was_installed_by_default());
1201 // Sync the chrome web store to maintain its position on the new tab page.
1202 is_syncable |= (id() == extension_misc::kWebStoreAppId);
1203 return is_syncable;
1204 }
1205
1206 bool Extension::RequiresSortOrdinal() const {
1207 return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
1208 }
1209
1210 bool Extension::ShouldDisplayInAppLauncher() const {
1211 // Only apps should be displayed in the launcher.
1212 return is_app() && display_in_launcher_;
1213 }
1214
1215 bool Extension::ShouldDisplayInNewTabPage() const {
1216 // Only apps should be displayed on the NTP.
1217 return is_app() && display_in_new_tab_page_;
1218 }
1219
1220 bool Extension::ShouldDisplayInExtensionSettings() const {
1221 // Don't show for themes since the settings UI isn't really useful for them.
1222 if (is_theme())
1223 return false;
1224
1225 // Don't show component extensions because they are only extensions as an
1226 // implementation detail of Chrome.
1227 if (location() == Extension::COMPONENT &&
1228 !CommandLine::ForCurrentProcess()->HasSwitch(
1229 switches::kShowComponentExtensionOptions)) {
1230 return false;
1231 }
1232
1233 // Always show unpacked extensions and apps.
1234 if (location() == Extension::LOAD)
1235 return true;
1236
1237 // Unless they are unpacked, never show hosted apps. Note: We intentionally
1238 // show packaged apps and platform apps because there are some pieces of
1239 // functionality that are only available in chrome://extensions/ but which
1240 // are needed for packaged and platform apps. For example, inspecting
1241 // background pages. See http://crbug.com/116134.
1242 if (is_hosted_app())
1243 return false;
1244
1245 return true;
1246 }
1247
1248 bool Extension::HasContentScriptAtURL(const GURL& url) const {
1249 for (UserScriptList::const_iterator it = content_scripts_.begin();
1250 it != content_scripts_.end(); ++it) {
1251 if (it->MatchesURL(url))
1252 return true;
1253 }
1254 return false;
1255 }
1256
1257 scoped_refptr<const PermissionSet> Extension::GetTabSpecificPermissions(
1258 int tab_id) const {
1259 base::AutoLock auto_lock(runtime_data_lock_);
1260 return runtime_data_.GetTabSpecificPermissions(tab_id);
1261 }
1262
1263 void Extension::UpdateTabSpecificPermissions(
1264 int tab_id,
1265 scoped_refptr<const PermissionSet> permissions) const {
1266 base::AutoLock auto_lock(runtime_data_lock_);
1267 runtime_data_.UpdateTabSpecificPermissions(tab_id, permissions);
1268 }
1269
1270 void Extension::ClearTabSpecificPermissions(int tab_id) const {
1271 base::AutoLock auto_lock(runtime_data_lock_);
1272 runtime_data_.ClearTabSpecificPermissions(tab_id);
1273 }
1274
1275 Extension::Location Extension::location() const {
1276 return manifest_->location();
1277 }
1278
1279 const std::string& Extension::id() const {
1280 return manifest_->extension_id();
1281 }
1282
1283 const std::string Extension::VersionString() const {
1284 return version()->GetString();
1285 }
1286
1287 void Extension::AddInstallWarnings(
1288 const InstallWarningVector& new_warnings) {
1289 install_warnings_.insert(install_warnings_.end(),
1290 new_warnings.begin(), new_warnings.end());
1291 }
1292
1293 bool Extension::is_platform_app() const {
1294 return manifest_->is_platform_app();
1295 }
1296
1297 bool Extension::is_hosted_app() const {
1298 return manifest()->is_hosted_app();
1299 }
1300
1301 bool Extension::is_legacy_packaged_app() const {
1302 return manifest()->is_legacy_packaged_app();
1303 }
1304
1305 bool Extension::is_theme() const {
1306 return manifest()->is_theme();
1307 }
1308
1309 GURL Extension::GetBackgroundURL() const {
1310 if (background_scripts_.empty())
1311 return background_url_;
1312 return GetResourceURL(extension_filenames::kGeneratedBackgroundPageFilename);
1313 }
1314
1315 Extension::RuntimeData::RuntimeData() {}
1316 Extension::RuntimeData::RuntimeData(const PermissionSet* active)
1317 : active_permissions_(active) {}
1318 Extension::RuntimeData::~RuntimeData() {}
1319
1320 void Extension::RuntimeData::SetActivePermissions(
1321 const PermissionSet* active) {
1322 active_permissions_ = active;
1323 }
1324
1325 scoped_refptr<const PermissionSet>
1326 Extension::RuntimeData::GetActivePermissions() const {
1327 return active_permissions_;
1328 }
1329
1330 scoped_refptr<const PermissionSet>
1331 Extension::RuntimeData::GetTabSpecificPermissions(int tab_id) const {
1332 CHECK_GE(tab_id, 0);
1333 TabPermissionsMap::const_iterator it = tab_specific_permissions_.find(tab_id);
1334 return (it != tab_specific_permissions_.end()) ? it->second : NULL;
1335 }
1336
1337 void Extension::RuntimeData::UpdateTabSpecificPermissions(
1338 int tab_id,
1339 scoped_refptr<const PermissionSet> permissions) {
1340 CHECK_GE(tab_id, 0);
1341 if (tab_specific_permissions_.count(tab_id)) {
1342 tab_specific_permissions_[tab_id] = PermissionSet::CreateUnion(
1343 tab_specific_permissions_[tab_id],
1344 permissions.get());
1345 } else {
1346 tab_specific_permissions_[tab_id] = permissions;
1347 }
1348 }
1349
1350 void Extension::RuntimeData::ClearTabSpecificPermissions(int tab_id) {
1351 CHECK_GE(tab_id, 0);
1352 tab_specific_permissions_.erase(tab_id);
976 } 1353 }
977 1354
978 // static 1355 // static
979 bool Extension::InitExtensionID(extensions::Manifest* manifest, 1356 bool Extension::InitExtensionID(extensions::Manifest* manifest,
980 const FilePath& path, 1357 const FilePath& path,
981 const std::string& explicit_id, 1358 const std::string& explicit_id,
982 int creation_flags, 1359 int creation_flags,
983 string16* error) { 1360 string16* error) {
984 if (!explicit_id.empty()) { 1361 if (!explicit_id.empty()) {
985 manifest->set_extension_id(explicit_id); 1362 manifest->set_extension_id(explicit_id);
(...skipping 24 matching lines...) Expand all
1010 std::string extension_id = GenerateIdForPath(path); 1387 std::string extension_id = GenerateIdForPath(path);
1011 if (extension_id.empty()) { 1388 if (extension_id.empty()) {
1012 NOTREACHED() << "Could not create ID from path."; 1389 NOTREACHED() << "Could not create ID from path.";
1013 return false; 1390 return false;
1014 } 1391 }
1015 manifest->set_extension_id(extension_id); 1392 manifest->set_extension_id(extension_id);
1016 return true; 1393 return true;
1017 } 1394 }
1018 } 1395 }
1019 1396
1397 // static
1398 FilePath Extension::MaybeNormalizePath(const FilePath& path) {
1399 #if defined(OS_WIN)
1400 // Normalize any drive letter to upper-case. We do this for consistency with
1401 // net_utils::FilePathToFileURL(), which does the same thing, to make string
1402 // comparisons simpler.
1403 std::wstring path_str = path.value();
1404 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
1405 path_str[1] == ':')
1406 path_str[0] += ('A' - 'a');
1407
1408 return FilePath(path_str);
1409 #else
1410 return path;
1411 #endif
1412 }
1413
1414 // static
1415 bool Extension::IsTrustedId(const std::string& id) {
1416 // See http://b/4946060 for more details.
1417 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
1418 }
1419
1420 Extension::Extension(const FilePath& path,
1421 scoped_ptr<extensions::Manifest> manifest)
1422 : manifest_version_(0),
1423 incognito_split_mode_(false),
1424 offline_enabled_(false),
1425 converted_from_user_script_(false),
1426 background_page_is_persistent_(true),
1427 allow_background_js_access_(true),
1428 manifest_(manifest.release()),
1429 is_storage_isolated_(false),
1430 launch_container_(extension_misc::LAUNCH_TAB),
1431 launch_width_(0),
1432 launch_height_(0),
1433 display_in_launcher_(true),
1434 display_in_new_tab_page_(true),
1435 wants_file_access_(false),
1436 creation_flags_(0) {
1437 DCHECK(path.empty() || path.IsAbsolute());
1438 path_ = MaybeNormalizePath(path);
1439 }
1440
1441 Extension::~Extension() {
1442 }
1443
1444 bool Extension::InitFromValue(int flags, string16* error) {
1445 DCHECK(error);
1446
1447 base::AutoLock auto_lock(runtime_data_lock_);
1448
1449 // Initialize permissions with an empty, default permission set.
1450 runtime_data_.SetActivePermissions(new PermissionSet());
1451 optional_permission_set_ = new PermissionSet();
1452 required_permission_set_ = new PermissionSet();
1453
1454 creation_flags_ = flags;
1455
1456 // Important to load manifest version first because many other features
1457 // depend on its value.
1458 if (!LoadManifestVersion(error))
1459 return false;
1460
1461 // Validate minimum Chrome version. We don't need to store this, since the
1462 // extension is not valid if it is incorrect
1463 if (!CheckMinimumChromeVersion(error))
1464 return false;
1465
1466 if (!LoadRequiredFeatures(error))
1467 return false;
1468
1469 // We don't need to validate because InitExtensionID already did that.
1470 manifest_->GetString(keys::kPublicKey, &public_key_);
1471
1472 extension_url_ = Extension::GetBaseURLFromExtensionId(id());
1473
1474 // Load App settings. LoadExtent at least has to be done before
1475 // ParsePermissions(), because the valid permissions depend on what type of
1476 // package this is.
1477 if (is_app() && !LoadAppFeatures(error))
1478 return false;
1479
1480 APIPermissionSet api_permissions;
1481 URLPatternSet host_permissions;
1482 if (!ParsePermissions(keys::kPermissions,
1483 error,
1484 &api_permissions,
1485 &host_permissions)) {
1486 return false;
1487 }
1488
1489 // TODO(jeremya/kalman) do this via the features system by exposing the
1490 // app.window API to platform apps, with no dependency on any permissions.
1491 // See http://crbug.com/120069.
1492 if (is_platform_app()) {
1493 api_permissions.insert(APIPermission::kAppCurrentWindowInternal);
1494 api_permissions.insert(APIPermission::kAppRuntime);
1495 api_permissions.insert(APIPermission::kAppWindow);
1496 }
1497
1498 if (from_webstore()) {
1499 details_url_ =
1500 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id());
1501 }
1502
1503 APIPermissionSet optional_api_permissions;
1504 URLPatternSet optional_host_permissions;
1505 if (!ParsePermissions(keys::kOptionalPermissions,
1506 error,
1507 &optional_api_permissions,
1508 &optional_host_permissions)) {
1509 return false;
1510 }
1511
1512 if (!LoadAppIsolation(api_permissions, error))
1513 return false;
1514
1515 if (!LoadSharedFeatures(api_permissions, error))
1516 return false;
1517
1518 if (!LoadExtensionFeatures(&api_permissions, error))
1519 return false;
1520
1521 if (!LoadThemeFeatures(error))
1522 return false;
1523
1524 if (HasMultipleUISurfaces()) {
1525 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly);
1526 return false;
1527 }
1528
1529 runtime_data_.SetActivePermissions(new PermissionSet(
1530 this, api_permissions, host_permissions));
1531 required_permission_set_ = new PermissionSet(
1532 this, api_permissions, host_permissions);
1533 optional_permission_set_ = new PermissionSet(
1534 optional_api_permissions, optional_host_permissions, URLPatternSet());
1535
1536 return true;
1537 }
1538
1539 bool Extension::LoadAppIsolation(const APIPermissionSet& api_permissions,
1540 string16* error) {
1541 // Platform apps always get isolated storage.
1542 if (is_platform_app()) {
1543 is_storage_isolated_ = true;
1544 return true;
1545 }
1546
1547 // Other apps only get it if it is requested _and_ experimental APIs are
1548 // enabled.
1549 if (!api_permissions.count(APIPermission::kExperimental) || !is_app())
1550 return true;
1551
1552 Value* tmp_isolation = NULL;
1553 if (!manifest_->Get(keys::kIsolation, &tmp_isolation))
1554 return true;
1555
1556 if (tmp_isolation->GetType() != Value::TYPE_LIST) {
1557 *error = ASCIIToUTF16(errors::kInvalidIsolation);
1558 return false;
1559 }
1560
1561 ListValue* isolation_list = static_cast<ListValue*>(tmp_isolation);
1562 for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
1563 std::string isolation_string;
1564 if (!isolation_list->GetString(i, &isolation_string)) {
1565 *error = ErrorUtils::FormatErrorMessageUTF16(
1566 errors::kInvalidIsolationValue,
1567 base::UintToString(i));
1568 return false;
1569 }
1570
1571 // Check for isolated storage.
1572 if (isolation_string == values::kIsolatedStorage) {
1573 is_storage_isolated_ = true;
1574 } else {
1575 DLOG(WARNING) << "Did not recognize isolation type: " << isolation_string;
1576 }
1577 }
1578 return true;
1579 }
1580
1020 bool Extension::LoadRequiredFeatures(string16* error) { 1581 bool Extension::LoadRequiredFeatures(string16* error) {
1021 if (!LoadName(error) || 1582 if (!LoadName(error) ||
1022 !LoadVersion(error)) 1583 !LoadVersion(error))
1023 return false; 1584 return false;
1024 return true; 1585 return true;
1025 } 1586 }
1026 1587
1027 bool Extension::LoadName(string16* error) { 1588 bool Extension::LoadName(string16* error) {
1028 string16 localized_name; 1589 string16 localized_name;
1029 if (!manifest_->GetString(keys::kName, &localized_name)) { 1590 if (!manifest_->GetString(keys::kName, &localized_name)) {
1030 *error = ASCIIToUTF16(errors::kInvalidName); 1591 *error = ASCIIToUTF16(errors::kInvalidName);
1031 return false; 1592 return false;
1032 } 1593 }
1033 non_localized_name_ = UTF16ToUTF8(localized_name); 1594 non_localized_name_ = UTF16ToUTF8(localized_name);
1034 base::i18n::AdjustStringForLocaleDirection(&localized_name); 1595 base::i18n::AdjustStringForLocaleDirection(&localized_name);
1035 name_ = UTF16ToUTF8(localized_name); 1596 name_ = UTF16ToUTF8(localized_name);
1036 return true; 1597 return true;
1037 } 1598 }
1038 1599
1039 bool Extension::LoadDescription(string16* error) { 1600 bool Extension::LoadVersion(string16* error) {
1040 if (manifest_->HasKey(keys::kDescription) && 1601 std::string version_str;
1041 !manifest_->GetString(keys::kDescription, &description_)) { 1602 if (!manifest_->GetString(keys::kVersion, &version_str)) {
1042 *error = ASCIIToUTF16(errors::kInvalidDescription); 1603 *error = ASCIIToUTF16(errors::kInvalidVersion);
1604 return false;
1605 }
1606 version_.reset(new Version(version_str));
1607 if (!version_->IsValid() || version_->components().size() > 4) {
1608 *error = ASCIIToUTF16(errors::kInvalidVersion);
1043 return false; 1609 return false;
1044 } 1610 }
1045 return true; 1611 return true;
1046 } 1612 }
1047 1613
1048 bool Extension::LoadAppFeatures(string16* error) { 1614 bool Extension::LoadAppFeatures(string16* error) {
1049 if (!LoadExtent(keys::kWebURLs, &extent_, 1615 if (!LoadExtent(keys::kWebURLs, &extent_,
1050 errors::kInvalidWebURLs, errors::kInvalidWebURL, error) || 1616 errors::kInvalidWebURLs, errors::kInvalidWebURL, error) ||
1051 !LoadLaunchURL(error) || 1617 !LoadLaunchURL(error) ||
1052 !LoadLaunchContainer(error)) { 1618 !LoadLaunchContainer(error)) {
(...skipping 10 matching lines...) Expand all
1063 *error = ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage); 1629 *error = ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage);
1064 return false; 1630 return false;
1065 } 1631 }
1066 } else { 1632 } else {
1067 // Inherit default from display_in_launcher property. 1633 // Inherit default from display_in_launcher property.
1068 display_in_new_tab_page_ = display_in_launcher_; 1634 display_in_new_tab_page_ = display_in_launcher_;
1069 } 1635 }
1070 return true; 1636 return true;
1071 } 1637 }
1072 1638
1073 bool Extension::LoadOAuth2Info(string16* error) {
1074 if (!manifest_->HasKey(keys::kOAuth2))
1075 return true;
1076
1077 if (!manifest_->GetString(keys::kOAuth2ClientId, &oauth2_info_.client_id) ||
1078 oauth2_info_.client_id.empty()) {
1079 *error = ASCIIToUTF16(errors::kInvalidOAuth2ClientId);
1080 return false;
1081 }
1082
1083 ListValue* list = NULL;
1084 if (!manifest_->GetList(keys::kOAuth2Scopes, &list)) {
1085 *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
1086 return false;
1087 }
1088
1089 for (size_t i = 0; i < list->GetSize(); ++i) {
1090 std::string scope;
1091 if (!list->GetString(i, &scope)) {
1092 *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
1093 return false;
1094 }
1095 oauth2_info_.scopes.push_back(scope);
1096 }
1097
1098 return true;
1099 }
1100
1101 bool Extension::LoadExtent(const char* key, 1639 bool Extension::LoadExtent(const char* key,
1102 URLPatternSet* extent, 1640 URLPatternSet* extent,
1103 const char* list_error, 1641 const char* list_error,
1104 const char* value_error, 1642 const char* value_error,
1105 string16* error) { 1643 string16* error) {
1106 Value* temp_pattern_value = NULL; 1644 Value* temp_pattern_value = NULL;
1107 if (!manifest_->Get(key, &temp_pattern_value)) 1645 if (!manifest_->Get(key, &temp_pattern_value))
1108 return true; 1646 return true;
1109 1647
1110 if (temp_pattern_value->GetType() != Value::TYPE_LIST) { 1648 if (temp_pattern_value->GetType() != Value::TYPE_LIST) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1165 return false; 1703 return false;
1166 } 1704 }
1167 pattern.SetPath(pattern.path() + '*'); 1705 pattern.SetPath(pattern.path() + '*');
1168 1706
1169 extent->AddPattern(pattern); 1707 extent->AddPattern(pattern);
1170 } 1708 }
1171 1709
1172 return true; 1710 return true;
1173 } 1711 }
1174 1712
1713 bool Extension::LoadLaunchContainer(string16* error) {
1714 Value* tmp_launcher_container = NULL;
1715 if (!manifest_->Get(keys::kLaunchContainer, &tmp_launcher_container))
1716 return true;
1717
1718 std::string launch_container_string;
1719 if (!tmp_launcher_container->GetAsString(&launch_container_string)) {
1720 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
1721 return false;
1722 }
1723
1724 if (launch_container_string == values::kLaunchContainerPanel) {
1725 launch_container_ = extension_misc::LAUNCH_PANEL;
1726 } else if (launch_container_string == values::kLaunchContainerTab) {
1727 launch_container_ = extension_misc::LAUNCH_TAB;
1728 } else {
1729 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
1730 return false;
1731 }
1732
1733 bool can_specify_initial_size =
1734 launch_container_ == extension_misc::LAUNCH_PANEL ||
1735 launch_container_ == extension_misc::LAUNCH_WINDOW;
1736
1737 // Validate the container width if present.
1738 if (!ReadLaunchDimension(manifest_.get(),
1739 keys::kLaunchWidth,
1740 &launch_width_,
1741 can_specify_initial_size,
1742 error)) {
1743 return false;
1744 }
1745
1746 // Validate container height if present.
1747 if (!ReadLaunchDimension(manifest_.get(),
1748 keys::kLaunchHeight,
1749 &launch_height_,
1750 can_specify_initial_size,
1751 error)) {
1752 return false;
1753 }
1754
1755 return true;
1756 }
1757
1175 bool Extension::LoadLaunchURL(string16* error) { 1758 bool Extension::LoadLaunchURL(string16* error) {
1176 Value* temp = NULL; 1759 Value* temp = NULL;
1177 1760
1178 // launch URL can be either local (to chrome-extension:// root) or an absolute 1761 // launch URL can be either local (to chrome-extension:// root) or an absolute
1179 // web URL. 1762 // web URL.
1180 if (manifest_->Get(keys::kLaunchLocalPath, &temp)) { 1763 if (manifest_->Get(keys::kLaunchLocalPath, &temp)) {
1181 if (manifest_->Get(keys::kLaunchWebURL, NULL)) { 1764 if (manifest_->Get(keys::kLaunchWebURL, NULL)) {
1182 *error = ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive); 1765 *error = ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive);
1183 return false; 1766 return false;
1184 } 1767 }
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1277 } 1860 }
1278 } else if (id() == extension_misc::kChromeAppId) { 1861 } else if (id() == extension_misc::kChromeAppId) {
1279 // Override launch url to new tab. 1862 // Override launch url to new tab.
1280 launch_web_url_ = chrome::kChromeUINewTabURL; 1863 launch_web_url_ = chrome::kChromeUINewTabURL;
1281 extent_.ClearPatterns(); 1864 extent_.ClearPatterns();
1282 } 1865 }
1283 1866
1284 return true; 1867 return true;
1285 } 1868 }
1286 1869
1287 bool Extension::LoadLaunchContainer(string16* error) {
1288 Value* tmp_launcher_container = NULL;
1289 if (!manifest_->Get(keys::kLaunchContainer, &tmp_launcher_container))
1290 return true;
1291
1292 std::string launch_container_string;
1293 if (!tmp_launcher_container->GetAsString(&launch_container_string)) {
1294 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
1295 return false;
1296 }
1297
1298 if (launch_container_string == values::kLaunchContainerPanel) {
1299 launch_container_ = extension_misc::LAUNCH_PANEL;
1300 } else if (launch_container_string == values::kLaunchContainerTab) {
1301 launch_container_ = extension_misc::LAUNCH_TAB;
1302 } else {
1303 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
1304 return false;
1305 }
1306
1307 bool can_specify_initial_size =
1308 launch_container_ == extension_misc::LAUNCH_PANEL ||
1309 launch_container_ == extension_misc::LAUNCH_WINDOW;
1310
1311 // Validate the container width if present.
1312 if (!ReadLaunchDimension(manifest_.get(),
1313 keys::kLaunchWidth,
1314 &launch_width_,
1315 can_specify_initial_size,
1316 error)) {
1317 return false;
1318 }
1319
1320 // Validate container height if present.
1321 if (!ReadLaunchDimension(manifest_.get(),
1322 keys::kLaunchHeight,
1323 &launch_height_,
1324 can_specify_initial_size,
1325 error)) {
1326 return false;
1327 }
1328
1329 return true;
1330 }
1331
1332 bool Extension::LoadSharedFeatures( 1870 bool Extension::LoadSharedFeatures(
1333 const APIPermissionSet& api_permissions, 1871 const APIPermissionSet& api_permissions,
1334 string16* error) { 1872 string16* error) {
1335 if (!LoadDescription(error) || 1873 if (!LoadDescription(error) ||
1336 !LoadHomepageURL(error) || 1874 !LoadHomepageURL(error) ||
1337 !LoadUpdateURL(error) || 1875 !LoadUpdateURL(error) ||
1338 !LoadIcons(error) || 1876 !LoadIcons(error) ||
1339 !LoadCommands(error) || 1877 !LoadCommands(error) ||
1340 !LoadPlugins(error) || 1878 !LoadPlugins(error) ||
1341 !LoadNaClModules(error) || 1879 !LoadNaClModules(error) ||
1342 !LoadWebAccessibleResources(error) || 1880 !LoadWebAccessibleResources(error) ||
1343 !LoadSandboxedPages(error) || 1881 !LoadSandboxedPages(error) ||
1344 !LoadRequirements(error) || 1882 !LoadRequirements(error) ||
1345 !LoadDefaultLocale(error) || 1883 !LoadDefaultLocale(error) ||
1346 !LoadOfflineEnabled(error) || 1884 !LoadOfflineEnabled(error) ||
1347 !LoadOptionsPage(error) || 1885 !LoadOptionsPage(error) ||
1348 // LoadBackgroundScripts() must be called before LoadBackgroundPage(). 1886 // LoadBackgroundScripts() must be called before LoadBackgroundPage().
1349 !LoadBackgroundScripts(error) || 1887 !LoadBackgroundScripts(error) ||
1350 !LoadBackgroundPage(api_permissions, error) || 1888 !LoadBackgroundPage(api_permissions, error) ||
1351 !LoadBackgroundPersistent(api_permissions, error) || 1889 !LoadBackgroundPersistent(api_permissions, error) ||
1352 !LoadBackgroundAllowJSAccess(api_permissions, error) || 1890 !LoadBackgroundAllowJSAccess(api_permissions, error) ||
1353 !LoadWebIntentServices(error) || 1891 !LoadWebIntentServices(error) ||
1354 !LoadOAuth2Info(error)) 1892 !LoadOAuth2Info(error))
1355 return false; 1893 return false;
1356 1894
1357 return true; 1895 return true;
1358 } 1896 }
1359 1897
1360 bool Extension::LoadVersion(string16* error) { 1898 bool Extension::LoadDescription(string16* error) {
1361 std::string version_str; 1899 if (manifest_->HasKey(keys::kDescription) &&
1362 if (!manifest_->GetString(keys::kVersion, &version_str)) { 1900 !manifest_->GetString(keys::kDescription, &description_)) {
1363 *error = ASCIIToUTF16(errors::kInvalidVersion); 1901 *error = ASCIIToUTF16(errors::kInvalidDescription);
1364 return false;
1365 }
1366 version_.reset(new Version(version_str));
1367 if (!version_->IsValid() || version_->components().size() > 4) {
1368 *error = ASCIIToUTF16(errors::kInvalidVersion);
1369 return false; 1902 return false;
1370 } 1903 }
1371 return true; 1904 return true;
1372 } 1905 }
1373 1906
1374 bool Extension::LoadManifestVersion(string16* error) { 1907 bool Extension::LoadManifestVersion(string16* error) {
1375 // Get the original value out of the dictionary so that we can validate it 1908 // Get the original value out of the dictionary so that we can validate it
1376 // more strictly. 1909 // more strictly.
1377 if (manifest_->value()->HasKey(keys::kManifestVersion)) { 1910 if (manifest_->value()->HasKey(keys::kManifestVersion)) {
1378 int manifest_version = 1; 1911 int manifest_version = 1;
(...skipping 1060 matching lines...) Expand 10 before | Expand all | Expand 10 after
2439 return false; 2972 return false;
2440 } 2973 }
2441 2974
2442 browser_action_info_ = LoadExtensionActionInfoHelper( 2975 browser_action_info_ = LoadExtensionActionInfoHelper(
2443 browser_action_value, Extension::ActionInfo::TYPE_BROWSER, error); 2976 browser_action_value, Extension::ActionInfo::TYPE_BROWSER, error);
2444 if (!browser_action_info_.get()) 2977 if (!browser_action_info_.get())
2445 return false; // Failed to parse browser action definition. 2978 return false; // Failed to parse browser action definition.
2446 return true; 2979 return true;
2447 } 2980 }
2448 2981
2449 bool Extension::LoadSystemIndicator(APIPermissionSet* api_permissions,
2450 string16* error) {
2451 if (!manifest_->HasKey(keys::kSystemIndicator)) {
2452 // There was no manifest entry for the system indicator.
2453 return true;
2454 }
2455
2456 DictionaryValue* system_indicator_value = NULL;
2457 if (!manifest_->GetDictionary(keys::kSystemIndicator,
2458 &system_indicator_value)) {
2459 *error = ASCIIToUTF16(errors::kInvalidSystemIndicator);
2460 return false;
2461 }
2462
2463 system_indicator_info_ = LoadExtensionActionInfoHelper(
2464 system_indicator_value,
2465 Extension::ActionInfo::TYPE_SYSTEM_INDICATOR,
2466 error);
2467
2468 if (!system_indicator_info_.get()) {
2469 return false;
2470 }
2471
2472 // Because the manifest was successfully parsed, auto-grant the permission.
2473 // TODO(dewittj) Add this for all extension action APIs.
2474 api_permissions->insert(APIPermission::kSystemIndicator);
2475
2476 return true;
2477 }
2478
2479 bool Extension::LoadScriptBadge(string16* error) { 2982 bool Extension::LoadScriptBadge(string16* error) {
2480 if (manifest_->HasKey(keys::kScriptBadge)) { 2983 if (manifest_->HasKey(keys::kScriptBadge)) {
2481 if (!FeatureSwitch::script_badges()->IsEnabled()) { 2984 if (!FeatureSwitch::script_badges()->IsEnabled()) {
2482 // So as to not confuse developers if they specify a script badge section 2985 // So as to not confuse developers if they specify a script badge section
2483 // in the manifest, show a warning if the script badge declaration isn't 2986 // in the manifest, show a warning if the script badge declaration isn't
2484 // going to have any effect. 2987 // going to have any effect.
2485 install_warnings_.push_back( 2988 install_warnings_.push_back(
2486 InstallWarning(InstallWarning::FORMAT_TEXT, 2989 InstallWarning(InstallWarning::FORMAT_TEXT,
2487 errors::kScriptBadgeRequiresFlag)); 2990 errors::kScriptBadgeRequiresFlag));
2488 } 2991 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2525 std::string path = icons().Get(extension_misc::kScriptBadgeIconSizes[i], 3028 std::string path = icons().Get(extension_misc::kScriptBadgeIconSizes[i],
2526 ExtensionIconSet::MATCH_BIGGER); 3029 ExtensionIconSet::MATCH_BIGGER);
2527 if (!path.empty()) 3030 if (!path.empty())
2528 script_badge_info_->default_icon.Add( 3031 script_badge_info_->default_icon.Add(
2529 extension_misc::kScriptBadgeIconSizes[i], path); 3032 extension_misc::kScriptBadgeIconSizes[i], path);
2530 } 3033 }
2531 3034
2532 return true; 3035 return true;
2533 } 3036 }
2534 3037
3038 bool Extension::LoadSystemIndicator(APIPermissionSet* api_permissions,
3039 string16* error) {
3040 if (!manifest_->HasKey(keys::kSystemIndicator)) {
3041 // There was no manifest entry for the system indicator.
3042 return true;
3043 }
3044
3045 DictionaryValue* system_indicator_value = NULL;
3046 if (!manifest_->GetDictionary(keys::kSystemIndicator,
3047 &system_indicator_value)) {
3048 *error = ASCIIToUTF16(errors::kInvalidSystemIndicator);
3049 return false;
3050 }
3051
3052 system_indicator_info_ = LoadExtensionActionInfoHelper(
3053 system_indicator_value,
3054 Extension::ActionInfo::TYPE_SYSTEM_INDICATOR,
3055 error);
3056
3057 if (!system_indicator_info_.get()) {
3058 return false;
3059 }
3060
3061 // Because the manifest was successfully parsed, auto-grant the permission.
3062 // TODO(dewittj) Add this for all extension action APIs.
3063 api_permissions->insert(APIPermission::kSystemIndicator);
3064
3065 return true;
3066 }
3067
2535 bool Extension::LoadFileBrowserHandlers(string16* error) { 3068 bool Extension::LoadFileBrowserHandlers(string16* error) {
2536 if (!manifest_->HasKey(keys::kFileBrowserHandlers)) 3069 if (!manifest_->HasKey(keys::kFileBrowserHandlers))
2537 return true; 3070 return true;
2538 ListValue* file_browser_handlers_value = NULL; 3071 ListValue* file_browser_handlers_value = NULL;
2539 if (!manifest_->GetList(keys::kFileBrowserHandlers, 3072 if (!manifest_->GetList(keys::kFileBrowserHandlers,
2540 &file_browser_handlers_value)) { 3073 &file_browser_handlers_value)) {
2541 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); 3074 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
2542 return false; 3075 return false;
2543 } 3076 }
2544 file_browser_handlers_.reset( 3077 file_browser_handlers_.reset(
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
2879 // TODO(abarth): Should we continue to let extensions override the 3412 // TODO(abarth): Should we continue to let extensions override the
2880 // default Content-Security-Policy? 3413 // default Content-Security-Policy?
2881 content_security_policy_ = is_platform_app() ? 3414 content_security_policy_ = is_platform_app() ?
2882 kDefaultPlatformAppContentSecurityPolicy : 3415 kDefaultPlatformAppContentSecurityPolicy :
2883 kDefaultContentSecurityPolicy; 3416 kDefaultContentSecurityPolicy;
2884 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_, GetType())); 3417 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_, GetType()));
2885 } 3418 }
2886 return true; 3419 return true;
2887 } 3420 }
2888 3421
2889 bool Extension::LoadAppIsolation(const APIPermissionSet& api_permissions,
2890 string16* error) {
2891 // Platform apps always get isolated storage.
2892 if (is_platform_app()) {
2893 is_storage_isolated_ = true;
2894 return true;
2895 }
2896
2897 // Other apps only get it if it is requested _and_ experimental APIs are
2898 // enabled.
2899 if (!api_permissions.count(APIPermission::kExperimental) || !is_app())
2900 return true;
2901
2902 Value* tmp_isolation = NULL;
2903 if (!manifest_->Get(keys::kIsolation, &tmp_isolation))
2904 return true;
2905
2906 if (tmp_isolation->GetType() != Value::TYPE_LIST) {
2907 *error = ASCIIToUTF16(errors::kInvalidIsolation);
2908 return false;
2909 }
2910
2911 ListValue* isolation_list = static_cast<ListValue*>(tmp_isolation);
2912 for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
2913 std::string isolation_string;
2914 if (!isolation_list->GetString(i, &isolation_string)) {
2915 *error = ErrorUtils::FormatErrorMessageUTF16(
2916 errors::kInvalidIsolationValue,
2917 base::UintToString(i));
2918 return false;
2919 }
2920
2921 // Check for isolated storage.
2922 if (isolation_string == values::kIsolatedStorage) {
2923 is_storage_isolated_ = true;
2924 } else {
2925 DLOG(WARNING) << "Did not recognize isolation type: " << isolation_string;
2926 }
2927 }
2928 return true;
2929 }
2930
2931 bool Extension::LoadThemeFeatures(string16* error) { 3422 bool Extension::LoadThemeFeatures(string16* error) {
2932 if (!manifest_->HasKey(keys::kTheme)) 3423 if (!manifest_->HasKey(keys::kTheme))
2933 return true; 3424 return true;
2934 DictionaryValue* theme_value = NULL; 3425 DictionaryValue* theme_value = NULL;
2935 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { 3426 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) {
2936 *error = ASCIIToUTF16(errors::kInvalidTheme); 3427 *error = ASCIIToUTF16(errors::kInvalidTheme);
2937 return false; 3428 return false;
2938 } 3429 }
2939 if (!LoadThemeImages(theme_value, error)) 3430 if (!LoadThemeImages(theme_value, error))
2940 return false; 3431 return false;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
3024 bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value, 3515 bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value,
3025 string16* error) { 3516 string16* error) {
3026 const DictionaryValue* display_properties_value = NULL; 3517 const DictionaryValue* display_properties_value = NULL;
3027 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, 3518 if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
3028 &display_properties_value)) { 3519 &display_properties_value)) {
3029 theme_display_properties_.reset( 3520 theme_display_properties_.reset(
3030 display_properties_value->DeepCopy()); 3521 display_properties_value->DeepCopy());
3031 } 3522 }
3032 return true; 3523 return true;
3033 } 3524 }
3034
3035 // static
3036 bool Extension::IsTrustedId(const std::string& id) {
3037 // See http://b/4946060 for more details.
3038 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
3039 }
3040
3041 Extension::Extension(const FilePath& path,
3042 scoped_ptr<extensions::Manifest> manifest)
3043 : manifest_version_(0),
3044 incognito_split_mode_(false),
3045 offline_enabled_(false),
3046 converted_from_user_script_(false),
3047 background_page_is_persistent_(true),
3048 allow_background_js_access_(true),
3049 manifest_(manifest.release()),
3050 is_storage_isolated_(false),
3051 launch_container_(extension_misc::LAUNCH_TAB),
3052 launch_width_(0),
3053 launch_height_(0),
3054 display_in_launcher_(true),
3055 display_in_new_tab_page_(true),
3056 wants_file_access_(false),
3057 creation_flags_(0) {
3058 DCHECK(path.empty() || path.IsAbsolute());
3059 path_ = MaybeNormalizePath(path);
3060 }
3061
3062 Extension::~Extension() {
3063 }
3064
3065 ExtensionResource Extension::GetResource(
3066 const std::string& relative_path) const {
3067 std::string new_path = relative_path;
3068 // We have some legacy data where resources have leading slashes.
3069 // See: http://crbug.com/121164
3070 if (!new_path.empty() && new_path.at(0) == '/')
3071 new_path.erase(0, 1);
3072 #if defined(OS_POSIX)
3073 FilePath relative_file_path(new_path);
3074 #elif defined(OS_WIN)
3075 FilePath relative_file_path(UTF8ToWide(new_path));
3076 #endif
3077 ExtensionResource r(id(), path(), relative_file_path);
3078 if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
3079 r.set_follow_symlinks_anywhere();
3080 }
3081 return r;
3082 }
3083
3084 ExtensionResource Extension::GetResource(
3085 const FilePath& relative_file_path) const {
3086 ExtensionResource r(id(), path(), relative_file_path);
3087 if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
3088 r.set_follow_symlinks_anywhere();
3089 }
3090 return r;
3091 }
3092
3093 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
3094 // util class in base:
3095 // http://code.google.com/p/chromium/issues/detail?id=13572
3096 bool Extension::ParsePEMKeyBytes(const std::string& input,
3097 std::string* output) {
3098 DCHECK(output);
3099 if (!output)
3100 return false;
3101 if (input.length() == 0)
3102 return false;
3103
3104 std::string working = input;
3105 if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
3106 working = CollapseWhitespaceASCII(working, true);
3107 size_t header_pos = working.find(kKeyInfoEndMarker,
3108 sizeof(kKeyBeginHeaderMarker) - 1);
3109 if (header_pos == std::string::npos)
3110 return false;
3111 size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
3112 size_t end_pos = working.rfind(kKeyBeginFooterMarker);
3113 if (end_pos == std::string::npos)
3114 return false;
3115 if (start_pos >= end_pos)
3116 return false;
3117
3118 working = working.substr(start_pos, end_pos - start_pos);
3119 if (working.length() == 0)
3120 return false;
3121 }
3122
3123 return base::Base64Decode(working, output);
3124 }
3125
3126 bool Extension::ProducePEM(const std::string& input, std::string* output) {
3127 DCHECK(output);
3128 return (input.length() == 0) ? false : base::Base64Encode(input, output);
3129 }
3130
3131 bool Extension::FormatPEMForFileOutput(const std::string& input,
3132 std::string* output,
3133 bool is_public) {
3134 DCHECK(output);
3135 if (input.length() == 0)
3136 return false;
3137 *output = "";
3138 output->append(kKeyBeginHeaderMarker);
3139 output->append(" ");
3140 output->append(is_public ? kPublic : kPrivate);
3141 output->append(" ");
3142 output->append(kKeyInfoEndMarker);
3143 output->append("\n");
3144 for (size_t i = 0; i < input.length(); ) {
3145 int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
3146 output->append(input.substr(i, slice));
3147 output->append("\n");
3148 i += slice;
3149 }
3150 output->append(kKeyBeginFooterMarker);
3151 output->append(" ");
3152 output->append(is_public ? kPublic : kPrivate);
3153 output->append(" ");
3154 output->append(kKeyInfoEndMarker);
3155 output->append("\n");
3156
3157 return true;
3158 }
3159
3160 // static
3161 void Extension::DecodeIcon(const Extension* extension,
3162 int preferred_icon_size,
3163 ExtensionIconSet::MatchType match_type,
3164 scoped_ptr<SkBitmap>* result) {
3165 std::string path = extension->icons().Get(preferred_icon_size, match_type);
3166 int size = extension->icons().GetIconSizeFromPath(path);
3167 ExtensionResource icon_resource = extension->GetResource(path);
3168 DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
3169 }
3170
3171 // static
3172 void Extension::DecodeIcon(const Extension* extension,
3173 int icon_size,
3174 scoped_ptr<SkBitmap>* result) {
3175 DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
3176 }
3177
3178 // static
3179 void Extension::DecodeIconFromPath(const FilePath& icon_path,
3180 int icon_size,
3181 scoped_ptr<SkBitmap>* result) {
3182 if (icon_path.empty())
3183 return;
3184
3185 std::string file_contents;
3186 if (!file_util::ReadFileToString(icon_path, &file_contents)) {
3187 DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
3188 return;
3189 }
3190
3191 // Decode the image using WebKit's image decoder.
3192 const unsigned char* data =
3193 reinterpret_cast<const unsigned char*>(file_contents.data());
3194 webkit_glue::ImageDecoder decoder;
3195 scoped_ptr<SkBitmap> decoded(new SkBitmap());
3196 *decoded = decoder.Decode(data, file_contents.length());
3197 if (decoded->empty()) {
3198 DLOG(ERROR) << "Could not decode icon file: "
3199 << icon_path.LossyDisplayName();
3200 return;
3201 }
3202
3203 if (decoded->width() != icon_size || decoded->height() != icon_size) {
3204 DLOG(ERROR) << "Icon file has unexpected size: "
3205 << base::IntToString(decoded->width()) << "x"
3206 << base::IntToString(decoded->height());
3207 return;
3208 }
3209
3210 result->swap(decoded);
3211 }
3212
3213 // static
3214 const gfx::ImageSkia& Extension::GetDefaultIcon(bool is_app) {
3215 int id = is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON;
3216 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
3217 }
3218
3219 // static
3220 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
3221 return GURL(std::string(extensions::kExtensionScheme) +
3222 content::kStandardSchemeSeparator + extension_id + "/");
3223 }
3224
3225 bool Extension::InitFromValue(int flags, string16* error) {
3226 DCHECK(error);
3227
3228 base::AutoLock auto_lock(runtime_data_lock_);
3229
3230 // Initialize permissions with an empty, default permission set.
3231 runtime_data_.SetActivePermissions(new PermissionSet());
3232 optional_permission_set_ = new PermissionSet();
3233 required_permission_set_ = new PermissionSet();
3234
3235 creation_flags_ = flags;
3236
3237 // Important to load manifest version first because many other features
3238 // depend on its value.
3239 if (!LoadManifestVersion(error))
3240 return false;
3241
3242 // Validate minimum Chrome version. We don't need to store this, since the
3243 // extension is not valid if it is incorrect
3244 if (!CheckMinimumChromeVersion(error))
3245 return false;
3246
3247 if (!LoadRequiredFeatures(error))
3248 return false;
3249
3250 // We don't need to validate because InitExtensionID already did that.
3251 manifest_->GetString(keys::kPublicKey, &public_key_);
3252
3253 extension_url_ = Extension::GetBaseURLFromExtensionId(id());
3254
3255 // Load App settings. LoadExtent at least has to be done before
3256 // ParsePermissions(), because the valid permissions depend on what type of
3257 // package this is.
3258 if (is_app() && !LoadAppFeatures(error))
3259 return false;
3260
3261 APIPermissionSet api_permissions;
3262 URLPatternSet host_permissions;
3263 if (!ParsePermissions(keys::kPermissions,
3264 error,
3265 &api_permissions,
3266 &host_permissions)) {
3267 return false;
3268 }
3269
3270 // TODO(jeremya/kalman) do this via the features system by exposing the
3271 // app.window API to platform apps, with no dependency on any permissions.
3272 // See http://crbug.com/120069.
3273 if (is_platform_app()) {
3274 api_permissions.insert(APIPermission::kAppCurrentWindowInternal);
3275 api_permissions.insert(APIPermission::kAppRuntime);
3276 api_permissions.insert(APIPermission::kAppWindow);
3277 }
3278
3279 if (from_webstore()) {
3280 details_url_ =
3281 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id());
3282 }
3283
3284 APIPermissionSet optional_api_permissions;
3285 URLPatternSet optional_host_permissions;
3286 if (!ParsePermissions(keys::kOptionalPermissions,
3287 error,
3288 &optional_api_permissions,
3289 &optional_host_permissions)) {
3290 return false;
3291 }
3292
3293 if (!LoadAppIsolation(api_permissions, error))
3294 return false;
3295
3296 if (!LoadSharedFeatures(api_permissions, error))
3297 return false;
3298
3299 if (!LoadExtensionFeatures(&api_permissions, error))
3300 return false;
3301
3302 if (!LoadThemeFeatures(error))
3303 return false;
3304
3305 if (HasMultipleUISurfaces()) {
3306 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly);
3307 return false;
3308 }
3309
3310 runtime_data_.SetActivePermissions(new PermissionSet(
3311 this, api_permissions, host_permissions));
3312 required_permission_set_ = new PermissionSet(
3313 this, api_permissions, host_permissions);
3314 optional_permission_set_ = new PermissionSet(
3315 optional_api_permissions, optional_host_permissions, URLPatternSet());
3316
3317 return true;
3318 }
3319
3320 GURL Extension::GetHomepageURL() const {
3321 if (homepage_url_.is_valid())
3322 return homepage_url_;
3323
3324 return UpdatesFromGallery() ?
3325 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + id()) : GURL();
3326 }
3327
3328 std::set<FilePath> Extension::GetBrowserImages() const {
3329 std::set<FilePath> image_paths;
3330 // TODO(viettrungluu): These |FilePath::FromWStringHack(UTF8ToWide())|
3331 // indicate that we're doing something wrong.
3332
3333 // Extension icons.
3334 for (ExtensionIconSet::IconMap::const_iterator iter = icons().map().begin();
3335 iter != icons().map().end(); ++iter) {
3336 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
3337 }
3338
3339 // Theme images.
3340 DictionaryValue* theme_images = GetThemeImages();
3341 if (theme_images) {
3342 for (DictionaryValue::key_iterator it = theme_images->begin_keys();
3343 it != theme_images->end_keys(); ++it) {
3344 std::string val;
3345 if (theme_images->GetStringWithoutPathExpansion(*it, &val))
3346 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(val)));
3347 }
3348 }
3349
3350 if (page_action_info() && !page_action_info()->default_icon.empty()) {
3351 for (ExtensionIconSet::IconMap::const_iterator iter =
3352 page_action_info()->default_icon.map().begin();
3353 iter != page_action_info()->default_icon.map().end();
3354 ++iter) {
3355 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
3356 }
3357 }
3358
3359 if (browser_action_info() && !browser_action_info()->default_icon.empty()) {
3360 for (ExtensionIconSet::IconMap::const_iterator iter =
3361 browser_action_info()->default_icon.map().begin();
3362 iter != browser_action_info()->default_icon.map().end();
3363 ++iter) {
3364 image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
3365 }
3366 }
3367
3368 return image_paths;
3369 }
3370
3371 GURL Extension::GetFullLaunchURL() const {
3372 return launch_local_path().empty() ? GURL(launch_web_url()) :
3373 url().Resolve(launch_local_path());
3374 }
3375
3376 static std::string SizeToString(const gfx::Size& max_size) {
3377 return base::IntToString(max_size.width()) + "x" +
3378 base::IntToString(max_size.height());
3379 }
3380
3381 // static
3382 void Extension::SetScriptingWhitelist(
3383 const Extension::ScriptingWhitelist& whitelist) {
3384 ScriptingWhitelist* current_whitelist =
3385 ExtensionConfig::GetInstance()->whitelist();
3386 current_whitelist->clear();
3387 for (ScriptingWhitelist::const_iterator it = whitelist.begin();
3388 it != whitelist.end(); ++it) {
3389 current_whitelist->push_back(*it);
3390 }
3391 }
3392
3393 // static
3394 const Extension::ScriptingWhitelist* Extension::GetScriptingWhitelist() {
3395 return ExtensionConfig::GetInstance()->whitelist();
3396 }
3397
3398 void Extension::SetCachedImage(const ExtensionResource& source,
3399 const SkBitmap& image,
3400 const gfx::Size& original_size) const {
3401 DCHECK(source.extension_root() == path()); // The resource must come from
3402 // this extension.
3403 const FilePath& path = source.relative_path();
3404 gfx::Size actual_size(image.width(), image.height());
3405 std::string location;
3406 if (actual_size != original_size)
3407 location = SizeToString(actual_size);
3408 image_cache_[ImageCacheKey(path, location)] = image;
3409 }
3410
3411 bool Extension::HasCachedImage(const ExtensionResource& source,
3412 const gfx::Size& max_size) const {
3413 DCHECK(source.extension_root() == path()); // The resource must come from
3414 // this extension.
3415 return GetCachedImageImpl(source, max_size) != NULL;
3416 }
3417
3418 SkBitmap Extension::GetCachedImage(const ExtensionResource& source,
3419 const gfx::Size& max_size) const {
3420 DCHECK(source.extension_root() == path()); // The resource must come from
3421 // this extension.
3422 SkBitmap* image = GetCachedImageImpl(source, max_size);
3423 return image ? *image : SkBitmap();
3424 }
3425
3426 SkBitmap* Extension::GetCachedImageImpl(const ExtensionResource& source, 3525 SkBitmap* Extension::GetCachedImageImpl(const ExtensionResource& source,
3427 const gfx::Size& max_size) const { 3526 const gfx::Size& max_size) const {
3428 const FilePath& path = source.relative_path(); 3527 const FilePath& path = source.relative_path();
3429 3528
3430 // Look for exact size match. 3529 // Look for exact size match.
3431 ImageCache::iterator i = image_cache_.find( 3530 ImageCache::iterator i = image_cache_.find(
3432 ImageCacheKey(path, SizeToString(max_size))); 3531 ImageCacheKey(path, SizeToString(max_size)));
3433 if (i != image_cache_.end()) 3532 if (i != image_cache_.end())
3434 return &(i->second); 3533 return &(i->second);
3435 3534
3436 // If we have the original size version cached, return that if it's small 3535 // If we have the original size version cached, return that if it's small
3437 // enough. 3536 // enough.
3438 i = image_cache_.find(ImageCacheKey(path, std::string())); 3537 i = image_cache_.find(ImageCacheKey(path, std::string()));
3439 if (i != image_cache_.end()) { 3538 if (i != image_cache_.end()) {
3440 const SkBitmap& image = i->second; 3539 const SkBitmap& image = i->second;
3441 if (image.width() <= max_size.width() && 3540 if (image.width() <= max_size.width() &&
3442 image.height() <= max_size.height()) { 3541 image.height() <= max_size.height()) {
3443 return &(i->second); 3542 return &(i->second);
3444 } 3543 }
3445 } 3544 }
3446 3545
3447 return NULL; 3546 return NULL;
3448 } 3547 }
3449 3548
3450 ExtensionResource Extension::GetIconResource( 3549 // Helper method that loads a UserScript object from a dictionary in the
3451 int size, ExtensionIconSet::MatchType match_type) const { 3550 // content_script list of the manifest.
3452 std::string path = icons().Get(size, match_type); 3551 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
3453 return path.empty() ? ExtensionResource() : GetResource(path); 3552 int definition_index,
3454 } 3553 string16* error,
3455 3554 UserScript* result) {
3456 GURL Extension::GetIconURL(int size, 3555 // run_at
3457 ExtensionIconSet::MatchType match_type) const { 3556 if (content_script->HasKey(keys::kRunAt)) {
3458 std::string path = icons().Get(size, match_type); 3557 std::string run_location;
3459 return path.empty() ? GURL() : GetResourceURL(path); 3558 if (!content_script->GetString(keys::kRunAt, &run_location)) {
3460 } 3559 *error = ErrorUtils::FormatErrorMessageUTF16(
3461 3560 errors::kInvalidRunAt,
3462 bool Extension::ParsePermissions(const char* key, 3561 base::IntToString(definition_index));
3463 string16* error, 3562 return false;
3464 APIPermissionSet* api_permissions, 3563 }
3465 URLPatternSet* host_permissions) { 3564
3466 if (manifest_->HasKey(key)) { 3565 if (run_location == values::kRunAtDocumentStart) {
3467 ListValue* permissions = NULL; 3566 result->set_run_location(UserScript::DOCUMENT_START);
3468 if (!manifest_->GetList(key, &permissions)) { 3567 } else if (run_location == values::kRunAtDocumentEnd) {
3469 *error = ErrorUtils::FormatErrorMessageUTF16( 3568 result->set_run_location(UserScript::DOCUMENT_END);
3470 errors::kInvalidPermissions, ""); 3569 } else if (run_location == values::kRunAtDocumentIdle) {
3471 return false; 3570 result->set_run_location(UserScript::DOCUMENT_IDLE);
3472 } 3571 } else {
3473 3572 *error = ErrorUtils::FormatErrorMessageUTF16(
3474 // NOTE: We need to get the APIPermission before we check if features 3573 errors::kInvalidRunAt,
3475 // associated with them are available because the feature system does not 3574 base::IntToString(definition_index));
3476 // know about aliases. 3575 return false;
3477 3576 }
3478 std::vector<std::string> host_data; 3577 }
3479 if (!APIPermissionSet::ParseFromJSON(permissions, api_permissions, 3578
3480 error, &host_data)) 3579 // all frames
3481 return false; 3580 if (content_script->HasKey(keys::kAllFrames)) {
3482 3581 bool all_frames = false;
3483 // Verify feature availability of permissions. 3582 if (!content_script->GetBoolean(keys::kAllFrames, &all_frames)) {
3484 std::vector<APIPermission::ID> to_remove; 3583 *error = ErrorUtils::FormatErrorMessageUTF16(
3485 SimpleFeatureProvider* permission_features = 3584 errors::kInvalidAllFrames, base::IntToString(definition_index));
3486 SimpleFeatureProvider::GetPermissionFeatures(); 3585 return false;
3487 for (APIPermissionSet::const_iterator it = api_permissions->begin(); 3586 }
3488 it != api_permissions->end(); ++it) { 3587 result->set_match_all_frames(all_frames);
3489 extensions::Feature* feature = 3588 }
3490 permission_features->GetFeature(it->name()); 3589
3491 3590 // matches (required)
3492 // The feature should exist since we just got an APIPermission 3591 const ListValue* matches = NULL;
3493 // for it. The two systems should be updated together whenever a 3592 if (!content_script->GetList(keys::kMatches, &matches)) {
3494 // permission is added. 3593 *error = ErrorUtils::FormatErrorMessageUTF16(
3495 CHECK(feature); 3594 errors::kInvalidMatches,
3496 3595 base::IntToString(definition_index));
3497 Feature::Availability availability = 3596 return false;
3498 feature->IsAvailableToManifest( 3597 }
3499 id(), 3598
3500 GetType(), 3599 if (matches->GetSize() == 0) {
3501 Feature::ConvertLocation(location()), 3600 *error = ErrorUtils::FormatErrorMessageUTF16(
3502 manifest_version()); 3601 errors::kInvalidMatchCount,
3503 if (!availability.is_available()) { 3602 base::IntToString(definition_index));
3504 // Don't fail, but warn the developer that the manifest contains 3603 return false;
3505 // unrecognized permissions. This may happen legitimately if the 3604 }
3506 // extensions requests platform- or channel-specific permissions. 3605 for (size_t j = 0; j < matches->GetSize(); ++j) {
3507 install_warnings_.push_back(InstallWarning(InstallWarning::FORMAT_TEXT, 3606 std::string match_str;
3508 availability.message())); 3607 if (!matches->GetString(j, &match_str)) {
3509 to_remove.push_back(it->id()); 3608 *error = ErrorUtils::FormatErrorMessageUTF16(
3510 continue; 3609 errors::kInvalidMatch,
3511 } 3610 base::IntToString(definition_index),
3512 3611 base::IntToString(j),
3513 if (it->id() == APIPermission::kExperimental) { 3612 errors::kExpectString);
3514 if (!CanSpecifyExperimentalPermission()) { 3613 return false;
3515 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); 3614 }
3516 return false; 3615
3616 URLPattern pattern(UserScript::kValidUserScriptSchemes);
3617 if (CanExecuteScriptEverywhere())
3618 pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
3619
3620 URLPattern::ParseResult parse_result = pattern.Parse(match_str);
3621 if (parse_result != URLPattern::PARSE_SUCCESS) {
3622 *error = ErrorUtils::FormatErrorMessageUTF16(
3623 errors::kInvalidMatch,
3624 base::IntToString(definition_index),
3625 base::IntToString(j),
3626 URLPattern::GetParseResultString(parse_result));
3627 return false;
3628 }
3629
3630 if (pattern.MatchesScheme(chrome::kFileScheme) &&
3631 !CanExecuteScriptEverywhere()) {
3632 wants_file_access_ = true;
3633 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) {
3634 pattern.SetValidSchemes(
3635 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
3636 }
3637 }
3638
3639 result->add_url_pattern(pattern);
3640 }
3641
3642 // exclude_matches
3643 if (content_script->HasKey(keys::kExcludeMatches)) { // optional
3644 const ListValue* exclude_matches = NULL;
3645 if (!content_script->GetList(keys::kExcludeMatches, &exclude_matches)) {
3646 *error = ErrorUtils::FormatErrorMessageUTF16(
3647 errors::kInvalidExcludeMatches,
3648 base::IntToString(definition_index));
3649 return false;
3650 }
3651
3652 for (size_t j = 0; j < exclude_matches->GetSize(); ++j) {
3653 std::string match_str;
3654 if (!exclude_matches->GetString(j, &match_str)) {
3655 *error = ErrorUtils::FormatErrorMessageUTF16(
3656 errors::kInvalidExcludeMatch,
3657 base::IntToString(definition_index),
3658 base::IntToString(j),
3659 errors::kExpectString);
3660 return false;
3661 }
3662
3663 URLPattern pattern(UserScript::kValidUserScriptSchemes);
3664 if (CanExecuteScriptEverywhere())
3665 pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
3666 URLPattern::ParseResult parse_result = pattern.Parse(match_str);
3667 if (parse_result != URLPattern::PARSE_SUCCESS) {
3668 *error = ErrorUtils::FormatErrorMessageUTF16(
3669 errors::kInvalidExcludeMatch,
3670 base::IntToString(definition_index), base::IntToString(j),
3671 URLPattern::GetParseResultString(parse_result));
3672 return false;
3673 }
3674
3675 result->add_exclude_url_pattern(pattern);
3676 }
3677 }
3678
3679 // include/exclude globs (mostly for Greasemonkey compatibility)
3680 if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
3681 error, &UserScript::add_glob, result)) {
3682 return false;
3683 }
3684
3685 if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
3686 error, &UserScript::add_exclude_glob, result)) {
3687 return false;
3688 }
3689
3690 // js and css keys
3691 const ListValue* js = NULL;
3692 if (content_script->HasKey(keys::kJs) &&
3693 !content_script->GetList(keys::kJs, &js)) {
3694 *error = ErrorUtils::FormatErrorMessageUTF16(
3695 errors::kInvalidJsList,
3696 base::IntToString(definition_index));
3697 return false;
3698 }
3699
3700 const ListValue* css = NULL;
3701 if (content_script->HasKey(keys::kCss) &&
3702 !content_script->GetList(keys::kCss, &css)) {
3703 *error = ErrorUtils::
3704 FormatErrorMessageUTF16(errors::kInvalidCssList,
3705 base::IntToString(definition_index));
3706 return false;
3707 }
3708
3709 // The manifest needs to have at least one js or css user script definition.
3710 if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
3711 *error = ErrorUtils::FormatErrorMessageUTF16(
3712 errors::kMissingFile,
3713 base::IntToString(definition_index));
3714 return false;
3715 }
3716
3717 if (js) {
3718 for (size_t script_index = 0; script_index < js->GetSize();
3719 ++script_index) {
3720 const Value* value;
3721 std::string relative;
3722 if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
3723 *error = ErrorUtils::FormatErrorMessageUTF16(
3724 errors::kInvalidJs,
3725 base::IntToString(definition_index),
3726 base::IntToString(script_index));
3727 return false;
3728 }
3729 GURL url = GetResourceURL(relative);
3730 ExtensionResource resource = GetResource(relative);
3731 result->js_scripts().push_back(UserScript::File(
3732 resource.extension_root(), resource.relative_path(), url));
3733 }
3734 }
3735
3736 if (css) {
3737 for (size_t script_index = 0; script_index < css->GetSize();
3738 ++script_index) {
3739 const Value* value;
3740 std::string relative;
3741 if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
3742 *error = ErrorUtils::FormatErrorMessageUTF16(
3743 errors::kInvalidCss,
3744 base::IntToString(definition_index),
3745 base::IntToString(script_index));
3746 return false;
3747 }
3748 GURL url = GetResourceURL(relative);
3749 ExtensionResource resource = GetResource(relative);
3750 result->css_scripts().push_back(UserScript::File(
3751 resource.extension_root(), resource.relative_path(), url));
3752 }
3753 }
3754
3755 return true;
3756 }
3757
3758 bool Extension::LoadGlobsHelper(
3759 const DictionaryValue* content_script,
3760 int content_script_index,
3761 const char* globs_property_name,
3762 string16* error,
3763 void(UserScript::*add_method)(const std::string& glob),
3764 UserScript* instance) {
3765 if (!content_script->HasKey(globs_property_name))
3766 return true; // they are optional
3767
3768 const ListValue* list = NULL;
3769 if (!content_script->GetList(globs_property_name, &list)) {
3770 *error = ErrorUtils::FormatErrorMessageUTF16(
3771 errors::kInvalidGlobList,
3772 base::IntToString(content_script_index),
3773 globs_property_name);
3774 return false;
3775 }
3776
3777 for (size_t i = 0; i < list->GetSize(); ++i) {
3778 std::string glob;
3779 if (!list->GetString(i, &glob)) {
3780 *error = ErrorUtils::FormatErrorMessageUTF16(
3781 errors::kInvalidGlob,
3782 base::IntToString(content_script_index),
3783 globs_property_name,
3784 base::IntToString(i));
3785 return false;
3786 }
3787
3788 (instance->*add_method)(glob);
3789 }
3790
3791 return true;
3792 }
3793
3794 scoped_ptr<Extension::ActionInfo> Extension::LoadExtensionActionInfoHelper(
3795 const DictionaryValue* extension_action,
3796 ActionInfo::Type action_type,
3797 string16* error) {
3798 scoped_ptr<ActionInfo> result(new ActionInfo());
3799
3800 if (manifest_version_ == 1) {
3801 // kPageActionIcons is obsolete, and used by very few extensions. Continue
3802 // loading it, but only take the first icon as the default_icon path.
3803 const ListValue* icons = NULL;
3804 if (extension_action->HasKey(keys::kPageActionIcons) &&
3805 extension_action->GetList(keys::kPageActionIcons, &icons)) {
3806 for (ListValue::const_iterator iter = icons->begin();
3807 iter != icons->end(); ++iter) {
3808 std::string path;
3809 if (!(*iter)->GetAsString(&path) || !NormalizeAndValidatePath(&path)) {
3810 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
3811 return scoped_ptr<ActionInfo>();
3517 } 3812 }
3518 } 3813
3519 } 3814 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
3520 3815 break;
3521 // Remove permissions that are not available to this extension. 3816 }
3522 for (std::vector<APIPermission::ID>::const_iterator it = to_remove.begin(); 3817 }
3523 it != to_remove.end(); ++it) { 3818
3524 api_permissions->erase(*it); 3819 std::string id;
3525 } 3820 if (extension_action->HasKey(keys::kPageActionId)) {
3526 3821 if (!extension_action->GetString(keys::kPageActionId, &id)) {
3527 // Parse host pattern permissions. 3822 *error = ASCIIToUTF16(errors::kInvalidPageActionId);
3528 const int kAllowedSchemes = CanExecuteScriptEverywhere() ? 3823 return scoped_ptr<ActionInfo>();
3529 URLPattern::SCHEME_ALL : kValidHostPermissionSchemes; 3824 }
3530 3825 result->id = id;
3531 for (std::vector<std::string>::const_iterator it = host_data.begin(); 3826 }
3532 it != host_data.end(); ++it) { 3827 }
3533 const std::string& permission_str = *it; 3828
3534 3829 // Read the page action |default_icon| (optional).
3535 // Check if it's a host pattern permission. 3830 // The |default_icon| value can be either dictionary {icon size -> icon path}
3536 URLPattern pattern = URLPattern(kAllowedSchemes); 3831 // or non empty string value.
3537 URLPattern::ParseResult parse_result = pattern.Parse(permission_str); 3832 if (extension_action->HasKey(keys::kPageActionDefaultIcon)) {
3538 if (parse_result == URLPattern::PARSE_SUCCESS) { 3833 const DictionaryValue* icons_value = NULL;
3539 if (!CanSpecifyHostPermission(pattern, *api_permissions)) { 3834 std::string default_icon;
3540 *error = ErrorUtils::FormatErrorMessageUTF16( 3835 if (extension_action->GetDictionary(keys::kPageActionDefaultIcon,
3541 errors::kInvalidPermissionScheme, permission_str); 3836 &icons_value)) {
3542 return false; 3837 if (!LoadIconsFromDictionary(icons_value,
3543 } 3838 extension_misc::kExtensionActionIconSizes,
3544 3839 extension_misc::kNumExtensionActionIconSizes,
3545 // The path component is not used for host permissions, so we force it 3840 &result->default_icon,
3546 // to match all paths. 3841 error)) {
3547 pattern.SetPath("/*"); 3842 return scoped_ptr<ActionInfo>();
3548 3843 }
3549 if (pattern.MatchesScheme(chrome::kFileScheme) && 3844 } else if (extension_action->GetString(keys::kPageActionDefaultIcon,
3550 !CanExecuteScriptEverywhere()) { 3845 &default_icon) &&
3551 wants_file_access_ = true; 3846 NormalizeAndValidatePath(&default_icon)) {
3552 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) { 3847 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION,
3553 pattern.SetValidSchemes( 3848 default_icon);
3554 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); 3849 } else {
3555 } 3850 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
3556 } 3851 return scoped_ptr<ActionInfo>();
3557 3852 }
3558 host_permissions->AddPattern(pattern); 3853 }
3559 continue; 3854
3560 } 3855 // Read the page action title from |default_title| if present, |name| if not
3561 3856 // (both optional).
3562 // It's probably an unknown API permission. Do not throw an error so 3857 if (extension_action->HasKey(keys::kPageActionDefaultTitle)) {
3563 // extensions can retain backwards compatability (http://crbug.com/42742). 3858 if (!extension_action->GetString(keys::kPageActionDefaultTitle,
3564 install_warnings_.push_back(InstallWarning( 3859 &result->default_title)) {
3565 InstallWarning::FORMAT_TEXT, 3860 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
3566 base::StringPrintf( 3861 return scoped_ptr<ActionInfo>();
3567 "Permission '%s' is unknown or URL pattern is malformed.", 3862 }
3568 permission_str.c_str()))); 3863 } else if (manifest_version_ == 1 && extension_action->HasKey(keys::kName)) {
3569 } 3864 if (!extension_action->GetString(keys::kName, &result->default_title)) {
3570 } 3865 *error = ASCIIToUTF16(errors::kInvalidPageActionName);
3866 return scoped_ptr<ActionInfo>();
3867 }
3868 }
3869
3870 // Read the action's |popup| (optional).
3871 const char* popup_key = NULL;
3872 if (extension_action->HasKey(keys::kPageActionDefaultPopup))
3873 popup_key = keys::kPageActionDefaultPopup;
3874
3875 if (manifest_version_ == 1 &&
3876 extension_action->HasKey(keys::kPageActionPopup)) {
3877 if (popup_key) {
3878 *error = ErrorUtils::FormatErrorMessageUTF16(
3879 errors::kInvalidPageActionOldAndNewKeys,
3880 keys::kPageActionDefaultPopup,
3881 keys::kPageActionPopup);
3882 return scoped_ptr<ActionInfo>();
3883 }
3884 popup_key = keys::kPageActionPopup;
3885 }
3886
3887 if (popup_key) {
3888 const DictionaryValue* popup = NULL;
3889 std::string url_str;
3890
3891 if (extension_action->GetString(popup_key, &url_str)) {
3892 // On success, |url_str| is set. Nothing else to do.
3893 } else if (manifest_version_ == 1 &&
3894 extension_action->GetDictionary(popup_key, &popup)) {
3895 if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
3896 *error = ErrorUtils::FormatErrorMessageUTF16(
3897 errors::kInvalidPageActionPopupPath, "<missing>");
3898 return scoped_ptr<ActionInfo>();
3899 }
3900 } else {
3901 *error = ASCIIToUTF16(errors::kInvalidPageActionPopup);
3902 return scoped_ptr<ActionInfo>();
3903 }
3904
3905 if (!url_str.empty()) {
3906 // An empty string is treated as having no popup.
3907 result->default_popup_url = GetResourceURL(url_str);
3908 if (!result->default_popup_url.is_valid()) {
3909 *error = ErrorUtils::FormatErrorMessageUTF16(
3910 errors::kInvalidPageActionPopupPath, url_str);
3911 return scoped_ptr<ActionInfo>();
3912 }
3913 } else {
3914 DCHECK(result->default_popup_url.is_empty())
3915 << "Shouldn't be possible for the popup to be set.";
3916 }
3917 }
3918
3919 return result.Pass();
3920 }
3921
3922 bool Extension::LoadOAuth2Info(string16* error) {
3923 if (!manifest_->HasKey(keys::kOAuth2))
3924 return true;
3925
3926 if (!manifest_->GetString(keys::kOAuth2ClientId, &oauth2_info_.client_id) ||
3927 oauth2_info_.client_id.empty()) {
3928 *error = ASCIIToUTF16(errors::kInvalidOAuth2ClientId);
3929 return false;
3930 }
3931
3932 ListValue* list = NULL;
3933 if (!manifest_->GetList(keys::kOAuth2Scopes, &list)) {
3934 *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
3935 return false;
3936 }
3937
3938 for (size_t i = 0; i < list->GetSize(); ++i) {
3939 std::string scope;
3940 if (!list->GetString(i, &scope)) {
3941 *error = ASCIIToUTF16(errors::kInvalidOAuth2Scopes);
3942 return false;
3943 }
3944 oauth2_info_.scopes.push_back(scope);
3945 }
3946
3571 return true; 3947 return true;
3572 } 3948 }
3573 3949
3574 bool Extension::CanSilentlyIncreasePermissions() const { 3950 bool Extension::HasMultipleUISurfaces() const {
3575 return location() != INTERNAL; 3951 int num_surfaces = 0;
3952
3953 if (page_action_info())
3954 ++num_surfaces;
3955
3956 if (browser_action_info())
3957 ++num_surfaces;
3958
3959 if (is_app())
3960 ++num_surfaces;
3961
3962 return num_surfaces > 1;
3963 }
3964
3965 void Extension::OverrideLaunchUrl(const GURL& override_url) {
3966 GURL new_url(override_url);
3967 if (!new_url.is_valid()) {
3968 DLOG(WARNING) << "Invalid override url given for " << name();
3969 } else {
3970 if (new_url.has_port()) {
3971 DLOG(WARNING) << "Override URL passed for " << name()
3972 << " should not contain a port. Removing it.";
3973
3974 GURL::Replacements remove_port;
3975 remove_port.ClearPort();
3976 new_url = new_url.ReplaceComponents(remove_port);
3977 }
3978
3979 launch_web_url_ = new_url.spec();
3980
3981 URLPattern pattern(kValidWebExtentSchemes);
3982 URLPattern::ParseResult result = pattern.Parse(new_url.spec());
3983 DCHECK_EQ(result, URLPattern::PARSE_SUCCESS);
3984 pattern.SetPath(pattern.path() + '*');
3985 extent_.AddPattern(pattern);
3986 }
3987 }
3988
3989 bool Extension::CanSpecifyExperimentalPermission() const {
3990 if (location() == Extension::COMPONENT)
3991 return true;
3992
3993 if (CommandLine::ForCurrentProcess()->HasSwitch(
3994 switches::kEnableExperimentalExtensionApis)) {
3995 return true;
3996 }
3997
3998 // We rely on the webstore to check access to experimental. This way we can
3999 // whitelist extensions to have access to experimental in just the store, and
4000 // not have to push a new version of the client.
4001 if (from_webstore())
4002 return true;
4003
4004 return false;
3576 } 4005 }
3577 4006
3578 bool Extension::CanSpecifyHostPermission(const URLPattern& pattern, 4007 bool Extension::CanSpecifyHostPermission(const URLPattern& pattern,
3579 const APIPermissionSet& permissions) const { 4008 const APIPermissionSet& permissions) const {
3580 if (!pattern.match_all_urls() && 4009 if (!pattern.match_all_urls() &&
3581 pattern.MatchesScheme(chrome::kChromeUIScheme)) { 4010 pattern.MatchesScheme(chrome::kChromeUIScheme)) {
3582 // Regular extensions are only allowed access to chrome://favicon. 4011 // Regular extensions are only allowed access to chrome://favicon.
3583 if (pattern.host() == chrome::kChromeUIFaviconHost) 4012 if (pattern.host() == chrome::kChromeUIFaviconHost)
3584 return true; 4013 return true;
3585 4014
3586 // Experimental extensions are also allowed chrome://thumb. 4015 // Experimental extensions are also allowed chrome://thumb.
3587 if (pattern.host() == chrome::kChromeUIThumbnailHost) { 4016 if (pattern.host() == chrome::kChromeUIThumbnailHost) {
3588 return permissions.find(APIPermission::kExperimental) != 4017 return permissions.find(APIPermission::kExperimental) !=
3589 permissions.end(); 4018 permissions.end();
3590 } 4019 }
3591 4020
3592 // Component extensions can have access to all of chrome://*. 4021 // Component extensions can have access to all of chrome://*.
3593 if (CanExecuteScriptEverywhere()) 4022 if (CanExecuteScriptEverywhere())
3594 return true; 4023 return true;
3595 4024
3596 return false; 4025 return false;
3597 } 4026 }
3598 4027
3599 // Otherwise, the valid schemes were handled by URLPattern. 4028 // Otherwise, the valid schemes were handled by URLPattern.
3600 return true; 4029 return true;
3601 } 4030 }
3602 4031
3603 bool Extension::HasAPIPermission(APIPermission::ID permission) const {
3604 base::AutoLock auto_lock(runtime_data_lock_);
3605 return runtime_data_.GetActivePermissions()->HasAPIPermission(permission);
3606 }
3607
3608 bool Extension::HasAPIPermission(const std::string& function_name) const {
3609 base::AutoLock auto_lock(runtime_data_lock_);
3610 return runtime_data_.GetActivePermissions()->
3611 HasAccessToFunction(function_name);
3612 }
3613
3614 bool Extension::HasAPIPermissionForTab(int tab_id,
3615 APIPermission::ID permission) const {
3616 base::AutoLock auto_lock(runtime_data_lock_);
3617 if (runtime_data_.GetActivePermissions()->HasAPIPermission(permission))
3618 return true;
3619 scoped_refptr<const PermissionSet> tab_specific_permissions =
3620 runtime_data_.GetTabSpecificPermissions(tab_id);
3621 return tab_specific_permissions.get() &&
3622 tab_specific_permissions->HasAPIPermission(permission);
3623 }
3624
3625 bool Extension::CheckAPIPermissionWithParam(APIPermission::ID permission,
3626 const APIPermission::CheckParam* param) const {
3627 base::AutoLock auto_lock(runtime_data_lock_);
3628 return runtime_data_.GetActivePermissions()->
3629 CheckAPIPermissionWithParam(permission, param);
3630 }
3631
3632 const URLPatternSet& Extension::GetEffectiveHostPermissions() const {
3633 base::AutoLock auto_lock(runtime_data_lock_);
3634 return runtime_data_.GetActivePermissions()->effective_hosts();
3635 }
3636
3637 bool Extension::HasHostPermission(const GURL& url) const {
3638 if (url.SchemeIs(chrome::kChromeUIScheme) &&
3639 url.host() != chrome::kChromeUIFaviconHost &&
3640 url.host() != chrome::kChromeUIThumbnailHost &&
3641 location() != Extension::COMPONENT) {
3642 return false;
3643 }
3644
3645 base::AutoLock auto_lock(runtime_data_lock_);
3646 return runtime_data_.GetActivePermissions()->
3647 HasExplicitAccessToOrigin(url);
3648 }
3649
3650 bool Extension::HasEffectiveAccessToAllHosts() const {
3651 base::AutoLock auto_lock(runtime_data_lock_);
3652 return runtime_data_.GetActivePermissions()->HasEffectiveAccessToAllHosts();
3653 }
3654
3655 bool Extension::HasFullPermissions() const {
3656 base::AutoLock auto_lock(runtime_data_lock_);
3657 return runtime_data_.GetActivePermissions()->HasEffectiveFullAccess();
3658 }
3659
3660 PermissionMessages Extension::GetPermissionMessages() const {
3661 base::AutoLock auto_lock(runtime_data_lock_);
3662 if (IsTrustedId(id())) {
3663 return PermissionMessages();
3664 } else {
3665 return runtime_data_.GetActivePermissions()->GetPermissionMessages(
3666 GetType());
3667 }
3668 }
3669
3670 std::vector<string16> Extension::GetPermissionMessageStrings() const {
3671 base::AutoLock auto_lock(runtime_data_lock_);
3672 if (IsTrustedId(id()))
3673 return std::vector<string16>();
3674 else
3675 return runtime_data_.GetActivePermissions()->GetWarningMessages(GetType());
3676 }
3677
3678 bool Extension::ShouldSkipPermissionWarnings() const {
3679 return IsTrustedId(id());
3680 }
3681
3682 void Extension::SetActivePermissions(
3683 const PermissionSet* permissions) const {
3684 base::AutoLock auto_lock(runtime_data_lock_);
3685 runtime_data_.SetActivePermissions(permissions);
3686 }
3687
3688 scoped_refptr<const PermissionSet>
3689 Extension::GetActivePermissions() const {
3690 base::AutoLock auto_lock(runtime_data_lock_);
3691 return runtime_data_.GetActivePermissions();
3692 }
3693
3694 bool Extension::HasMultipleUISurfaces() const {
3695 int num_surfaces = 0;
3696
3697 if (page_action_info())
3698 ++num_surfaces;
3699
3700 if (browser_action_info())
3701 ++num_surfaces;
3702
3703 if (is_app())
3704 ++num_surfaces;
3705
3706 return num_surfaces > 1;
3707 }
3708
3709 bool Extension::CanExecuteScriptOnPage(const GURL& document_url,
3710 const GURL& top_frame_url,
3711 int tab_id,
3712 const UserScript* script,
3713 std::string* error) const {
3714 base::AutoLock auto_lock(runtime_data_lock_);
3715 // The gallery is special-cased as a restricted URL for scripting to prevent
3716 // access to special JS bindings we expose to the gallery (and avoid things
3717 // like extensions removing the "report abuse" link).
3718 // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
3719 // against the store app extent?
3720 GURL store_url(extension_urls::GetWebstoreLaunchURL());
3721 if ((document_url.host() == store_url.host()) &&
3722 !CanExecuteScriptEverywhere() &&
3723 !CommandLine::ForCurrentProcess()->HasSwitch(
3724 switches::kAllowScriptingGallery)) {
3725 if (error)
3726 *error = errors::kCannotScriptGallery;
3727 return false;
3728 }
3729
3730 if (document_url.SchemeIs(chrome::kChromeUIScheme) &&
3731 !CanExecuteScriptEverywhere()) {
3732 return false;
3733 }
3734
3735 if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
3736 top_frame_url.GetOrigin() !=
3737 GetBaseURLFromExtensionId(id()).GetOrigin() &&
3738 !CanExecuteScriptEverywhere()) {
3739 return false;
3740 }
3741
3742 // If a tab ID is specified, try the tab-specific permissions.
3743 if (tab_id >= 0) {
3744 scoped_refptr<const PermissionSet> tab_permissions =
3745 runtime_data_.GetTabSpecificPermissions(tab_id);
3746 if (tab_permissions.get() &&
3747 tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
3748 return true;
3749 }
3750 }
3751
3752 // If a script is specified, use its matches.
3753 if (script)
3754 return script->MatchesURL(document_url);
3755
3756 // Otherwise, see if this extension has permission to execute script
3757 // programmatically on pages.
3758 if (runtime_data_.GetActivePermissions()->HasExplicitAccessToOrigin(
3759 document_url)) {
3760 return true;
3761 }
3762
3763 if (error) {
3764 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
3765 document_url.spec());
3766 }
3767
3768 return false;
3769 }
3770
3771 bool Extension::ShowConfigureContextMenus() const {
3772 // Don't show context menu for component extensions. We might want to show
3773 // options for component extension button but now there is no component
3774 // extension with options. All other menu items like uninstall have
3775 // no sense for component extensions.
3776 return location() != Extension::COMPONENT;
3777 }
3778
3779 bool Extension::CanSpecifyExperimentalPermission() const {
3780 if (location() == Extension::COMPONENT)
3781 return true;
3782
3783 if (CommandLine::ForCurrentProcess()->HasSwitch(
3784 switches::kEnableExperimentalExtensionApis)) {
3785 return true;
3786 }
3787
3788 // We rely on the webstore to check access to experimental. This way we can
3789 // whitelist extensions to have access to experimental in just the store, and
3790 // not have to push a new version of the client.
3791 if (from_webstore())
3792 return true;
3793
3794 return false;
3795 }
3796
3797 bool Extension::CanExecuteScriptEverywhere() const {
3798 if (location() == Extension::COMPONENT)
3799 return true;
3800
3801 ScriptingWhitelist* whitelist = ExtensionConfig::GetInstance()->whitelist();
3802
3803 for (ScriptingWhitelist::const_iterator it = whitelist->begin();
3804 it != whitelist->end(); ++it) {
3805 if (id() == *it) {
3806 return true;
3807 }
3808 }
3809
3810 return false;
3811 }
3812
3813 bool Extension::CanCaptureVisiblePage(const GURL& page_url,
3814 int tab_id,
3815 std::string* error) const {
3816 if (tab_id >= 0) {
3817 scoped_refptr<const PermissionSet> tab_permissions =
3818 GetTabSpecificPermissions(tab_id);
3819 if (tab_permissions.get() &&
3820 tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) {
3821 return true;
3822 }
3823 }
3824
3825 if (HasHostPermission(page_url) || page_url.GetOrigin() == url())
3826 return true;
3827
3828 if (error) {
3829 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
3830 page_url.spec());
3831 }
3832 return false;
3833 }
3834
3835 bool Extension::UpdatesFromGallery() const {
3836 return extension_urls::IsWebstoreUpdateUrl(update_url());
3837 }
3838
3839 bool Extension::OverlapsWithOrigin(const GURL& origin) const {
3840 if (url() == origin)
3841 return true;
3842
3843 if (web_extent().is_empty())
3844 return false;
3845
3846 // Note: patterns and extents ignore port numbers.
3847 URLPattern origin_only_pattern(kValidWebExtentSchemes);
3848 if (!origin_only_pattern.SetScheme(origin.scheme()))
3849 return false;
3850 origin_only_pattern.SetHost(origin.host());
3851 origin_only_pattern.SetPath("/*");
3852
3853 URLPatternSet origin_only_pattern_list;
3854 origin_only_pattern_list.AddPattern(origin_only_pattern);
3855
3856 return web_extent().OverlapsWith(origin_only_pattern_list);
3857 }
3858
3859 Extension::SyncType Extension::GetSyncType() const {
3860 if (!IsSyncable()) {
3861 // We have a non-standard location.
3862 return SYNC_TYPE_NONE;
3863 }
3864
3865 // Disallow extensions with non-gallery auto-update URLs for now.
3866 //
3867 // TODO(akalin): Relax this restriction once we've put in UI to
3868 // approve synced extensions.
3869 if (!update_url().is_empty() && !UpdatesFromGallery())
3870 return SYNC_TYPE_NONE;
3871
3872 // Disallow extensions with native code plugins.
3873 //
3874 // TODO(akalin): Relax this restriction once we've put in UI to
3875 // approve synced extensions.
3876 if (!plugins().empty()) {
3877 return SYNC_TYPE_NONE;
3878 }
3879
3880 switch (GetType()) {
3881 case Extension::TYPE_EXTENSION:
3882 return SYNC_TYPE_EXTENSION;
3883
3884 case Extension::TYPE_USER_SCRIPT:
3885 // We only want to sync user scripts with gallery update URLs.
3886 if (UpdatesFromGallery())
3887 return SYNC_TYPE_EXTENSION;
3888 else
3889 return SYNC_TYPE_NONE;
3890
3891 case Extension::TYPE_HOSTED_APP:
3892 case Extension::TYPE_LEGACY_PACKAGED_APP:
3893 case Extension::TYPE_PLATFORM_APP:
3894 return SYNC_TYPE_APP;
3895
3896 default:
3897 return SYNC_TYPE_NONE;
3898 }
3899 }
3900
3901 bool Extension::IsSyncable() const {
3902 // TODO(akalin): Figure out if we need to allow some other types.
3903
3904 // Default apps are not synced because otherwise they will pollute profiles
3905 // that don't already have them. Specially, if a user doesn't have default
3906 // apps, creates a new profile (which get default apps) and then enables sync
3907 // for it, then their profile everywhere gets the default apps.
3908 bool is_syncable = (location() == Extension::INTERNAL &&
3909 !was_installed_by_default());
3910 // Sync the chrome web store to maintain its position on the new tab page.
3911 is_syncable |= (id() == extension_misc::kWebStoreAppId);
3912 return is_syncable;
3913 }
3914
3915 bool Extension::RequiresSortOrdinal() const {
3916 return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
3917 }
3918
3919 bool Extension::ShouldDisplayInAppLauncher() const {
3920 // Only apps should be displayed in the launcher.
3921 return is_app() && display_in_launcher_;
3922 }
3923
3924 bool Extension::ShouldDisplayInNewTabPage() const {
3925 // Only apps should be displayed on the NTP.
3926 return is_app() && display_in_new_tab_page_;
3927 }
3928
3929 bool Extension::InstallWarning::operator==(const InstallWarning& other) const {
3930 return format == other.format && message == other.message;
3931 }
3932
3933 void PrintTo(const Extension::InstallWarning& warning, ::std::ostream* os) {
3934 *os << "InstallWarning(";
3935 switch (warning.format) {
3936 case Extension::InstallWarning::FORMAT_TEXT:
3937 *os << "FORMAT_TEXT, \"";
3938 break;
3939 case Extension::InstallWarning::FORMAT_HTML:
3940 *os << "FORMAT_HTML, \"";
3941 break;
3942 }
3943 // This is just for test error messages, so no need to escape '"'
3944 // characters inside the message.
3945 *os << warning.message << "\")";
3946 }
3947
3948 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
3949 const std::string& id,
3950 const FilePath& path,
3951 Extension::Location location)
3952 : extension_id(id),
3953 extension_path(path),
3954 extension_location(location) {
3955 if (manifest)
3956 extension_manifest.reset(manifest->DeepCopy());
3957 }
3958
3959 bool Extension::ShouldDisplayInExtensionSettings() const {
3960 // Don't show for themes since the settings UI isn't really useful for them.
3961 if (is_theme())
3962 return false;
3963
3964 // Don't show component extensions because they are only extensions as an
3965 // implementation detail of Chrome.
3966 if (location() == Extension::COMPONENT &&
3967 !CommandLine::ForCurrentProcess()->HasSwitch(
3968 switches::kShowComponentExtensionOptions)) {
3969 return false;
3970 }
3971
3972 // Always show unpacked extensions and apps.
3973 if (location() == Extension::LOAD)
3974 return true;
3975
3976 // Unless they are unpacked, never show hosted apps. Note: We intentionally
3977 // show packaged apps and platform apps because there are some pieces of
3978 // functionality that are only available in chrome://extensions/ but which
3979 // are needed for packaged and platform apps. For example, inspecting
3980 // background pages. See http://crbug.com/116134.
3981 if (is_hosted_app())
3982 return false;
3983
3984 return true;
3985 }
3986
3987 bool Extension::HasContentScriptAtURL(const GURL& url) const {
3988 for (UserScriptList::const_iterator it = content_scripts_.begin();
3989 it != content_scripts_.end(); ++it) {
3990 if (it->MatchesURL(url))
3991 return true;
3992 }
3993 return false;
3994 }
3995
3996 scoped_refptr<const PermissionSet> Extension::GetTabSpecificPermissions(
3997 int tab_id) const {
3998 base::AutoLock auto_lock(runtime_data_lock_);
3999 return runtime_data_.GetTabSpecificPermissions(tab_id);
4000 }
4001
4002 void Extension::UpdateTabSpecificPermissions(
4003 int tab_id,
4004 scoped_refptr<const PermissionSet> permissions) const {
4005 base::AutoLock auto_lock(runtime_data_lock_);
4006 runtime_data_.UpdateTabSpecificPermissions(tab_id, permissions);
4007 }
4008
4009 void Extension::ClearTabSpecificPermissions(int tab_id) const {
4010 base::AutoLock auto_lock(runtime_data_lock_);
4011 runtime_data_.ClearTabSpecificPermissions(tab_id);
4012 }
4013
4014 bool Extension::CheckMinimumChromeVersion(string16* error) const { 4032 bool Extension::CheckMinimumChromeVersion(string16* error) const {
4015 if (!manifest_->HasKey(keys::kMinimumChromeVersion)) 4033 if (!manifest_->HasKey(keys::kMinimumChromeVersion))
4016 return true; 4034 return true;
4017 std::string minimum_version_string; 4035 std::string minimum_version_string;
4018 if (!manifest_->GetString(keys::kMinimumChromeVersion, 4036 if (!manifest_->GetString(keys::kMinimumChromeVersion,
4019 &minimum_version_string)) { 4037 &minimum_version_string)) {
4020 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); 4038 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
4021 return false; 4039 return false;
4022 } 4040 }
4023 4041
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
4069 bool Extension::CheckConflictingFeatures(std::string* utf8_error) const { 4087 bool Extension::CheckConflictingFeatures(std::string* utf8_error) const {
4070 if (has_lazy_background_page() && 4088 if (has_lazy_background_page() &&
4071 HasAPIPermission(APIPermission::kWebRequest)) { 4089 HasAPIPermission(APIPermission::kWebRequest)) {
4072 *utf8_error = errors::kWebRequestConflictsWithLazyBackground; 4090 *utf8_error = errors::kWebRequestConflictsWithLazyBackground;
4073 return false; 4091 return false;
4074 } 4092 }
4075 4093
4076 return true; 4094 return true;
4077 } 4095 }
4078 4096
4097 void PrintTo(const Extension::InstallWarning& warning, ::std::ostream* os) {
4098 *os << "InstallWarning(";
4099 switch (warning.format) {
4100 case Extension::InstallWarning::FORMAT_TEXT:
4101 *os << "FORMAT_TEXT, \"";
4102 break;
4103 case Extension::InstallWarning::FORMAT_HTML:
4104 *os << "FORMAT_HTML, \"";
4105 break;
4106 }
4107 // This is just for test error messages, so no need to escape '"'
4108 // characters inside the message.
4109 *os << warning.message << "\")";
4110 }
4111
4112 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
4113 const std::string& id,
4114 const FilePath& path,
4115 Extension::Location location)
4116 : extension_id(id),
4117 extension_path(path),
4118 extension_location(location) {
4119 if (manifest)
4120 extension_manifest.reset(manifest->DeepCopy());
4121 }
4122
4079 ExtensionInfo::~ExtensionInfo() {} 4123 ExtensionInfo::~ExtensionInfo() {}
4080 4124
4081 Extension::RuntimeData::RuntimeData() {}
4082 Extension::RuntimeData::RuntimeData(const PermissionSet* active)
4083 : active_permissions_(active) {}
4084 Extension::RuntimeData::~RuntimeData() {}
4085
4086 scoped_refptr<const PermissionSet>
4087 Extension::RuntimeData::GetActivePermissions() const {
4088 return active_permissions_;
4089 }
4090
4091 void Extension::RuntimeData::SetActivePermissions(
4092 const PermissionSet* active) {
4093 active_permissions_ = active;
4094 }
4095
4096 scoped_refptr<const PermissionSet>
4097 Extension::RuntimeData::GetTabSpecificPermissions(int tab_id) const {
4098 CHECK_GE(tab_id, 0);
4099 TabPermissionsMap::const_iterator it = tab_specific_permissions_.find(tab_id);
4100 return (it != tab_specific_permissions_.end()) ? it->second : NULL;
4101 }
4102
4103 void Extension::RuntimeData::UpdateTabSpecificPermissions(
4104 int tab_id,
4105 scoped_refptr<const PermissionSet> permissions) {
4106 CHECK_GE(tab_id, 0);
4107 if (tab_specific_permissions_.count(tab_id)) {
4108 tab_specific_permissions_[tab_id] = PermissionSet::CreateUnion(
4109 tab_specific_permissions_[tab_id],
4110 permissions.get());
4111 } else {
4112 tab_specific_permissions_[tab_id] = permissions;
4113 }
4114 }
4115
4116 void Extension::RuntimeData::ClearTabSpecificPermissions(int tab_id) {
4117 CHECK_GE(tab_id, 0);
4118 tab_specific_permissions_.erase(tab_id);
4119 }
4120
4121 UnloadedExtensionInfo::UnloadedExtensionInfo( 4125 UnloadedExtensionInfo::UnloadedExtensionInfo(
4122 const Extension* extension, 4126 const Extension* extension,
4123 extension_misc::UnloadedExtensionReason reason) 4127 extension_misc::UnloadedExtensionReason reason)
4124 : reason(reason), 4128 : reason(reason),
4125 already_disabled(false), 4129 already_disabled(false),
4126 extension(extension) {} 4130 extension(extension) {}
4127 4131
4128 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 4132 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
4129 const Extension* extension, 4133 const Extension* extension,
4130 const PermissionSet* permissions, 4134 const PermissionSet* permissions,
4131 Reason reason) 4135 Reason reason)
4132 : reason(reason), 4136 : reason(reason),
4133 extension(extension), 4137 extension(extension),
4134 permissions(permissions) {} 4138 permissions(permissions) {}
4135 4139
4136 } // namespace extensions 4140 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698