Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 break; | 165 break; |
| 166 | 166 |
| 167 default: | 167 default: |
| 168 NOTREACHED() << "Need to add new extension locaton " << location; | 168 NOTREACHED() << "Need to add new extension locaton " << location; |
| 169 } | 169 } |
| 170 | 170 |
| 171 CHECK(rank != kInvalidRank); | 171 CHECK(rank != kInvalidRank); |
| 172 return rank; | 172 return rank; |
| 173 } | 173 } |
| 174 | 174 |
| 175 bool ReadLaunchDimension(const extensions::Manifest* manifest, | |
| 176 const char* key, | |
| 177 int* target, | |
| 178 bool is_valid_container, | |
| 179 string16* error) { | |
| 180 Value* temp = NULL; | |
| 181 if (manifest->Get(key, &temp)) { | |
| 182 if (!is_valid_container) { | |
| 183 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 184 errors::kInvalidLaunchValueContainer, | |
| 185 key); | |
| 186 return false; | |
| 187 } | |
| 188 if (!temp->GetAsInteger(target) || *target < 0) { | |
| 189 *target = 0; | |
| 190 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 191 errors::kInvalidLaunchValue, | |
| 192 key); | |
| 193 return false; | |
| 194 } | |
| 195 } | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 175 } // namespace | 199 } // namespace |
| 176 | 200 |
| 177 const FilePath::CharType Extension::kManifestFilename[] = | 201 const FilePath::CharType Extension::kManifestFilename[] = |
| 178 FILE_PATH_LITERAL("manifest.json"); | 202 FILE_PATH_LITERAL("manifest.json"); |
| 179 const FilePath::CharType Extension::kLocaleFolder[] = | 203 const FilePath::CharType Extension::kLocaleFolder[] = |
| 180 FILE_PATH_LITERAL("_locales"); | 204 FILE_PATH_LITERAL("_locales"); |
| 181 const FilePath::CharType Extension::kMessagesFilename[] = | 205 const FilePath::CharType Extension::kMessagesFilename[] = |
| 182 FILE_PATH_LITERAL("messages.json"); | 206 FILE_PATH_LITERAL("messages.json"); |
| 183 | 207 |
| 184 #if defined(OS_WIN) | 208 #if defined(OS_WIN) |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 utf8_error); | 350 utf8_error); |
| 327 } | 351 } |
| 328 | 352 |
| 329 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 353 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
| 330 Location location, | 354 Location location, |
| 331 const DictionaryValue& value, | 355 const DictionaryValue& value, |
| 332 int flags, | 356 int flags, |
| 333 const std::string& explicit_id, | 357 const std::string& explicit_id, |
| 334 std::string* utf8_error) { | 358 std::string* utf8_error) { |
| 335 DCHECK(utf8_error); | 359 DCHECK(utf8_error); |
| 336 | |
| 337 string16 error; | 360 string16 error; |
| 338 scoped_ptr<extensions::Manifest> manifest( | 361 scoped_ptr<extensions::Manifest> manifest( |
| 339 new extensions::Manifest( | 362 new extensions::Manifest( |
| 340 location, | 363 location, |
| 341 scoped_ptr<DictionaryValue>(value.DeepCopy()))); | 364 scoped_ptr<DictionaryValue>(value.DeepCopy()))); |
| 342 | 365 |
| 343 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error) || | 366 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error) || |
| 344 !manifest->ValidateManifest(&error)) { | 367 !manifest->ValidateManifest(&error)) { |
| 345 *utf8_error = UTF16ToUTF8(error); | 368 *utf8_error = UTF16ToUTF8(error); |
| 346 return NULL; | 369 return NULL; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false)); | 496 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false)); |
| 474 | 497 |
| 475 return ret_val; | 498 return ret_val; |
| 476 } | 499 } |
| 477 | 500 |
| 478 bool Extension::is_platform_app() const { | 501 bool Extension::is_platform_app() const { |
| 479 return manifest_->IsPlatformApp(); | 502 return manifest_->IsPlatformApp(); |
| 480 } | 503 } |
| 481 | 504 |
| 482 bool Extension::is_hosted_app() const { | 505 bool Extension::is_hosted_app() const { |
| 483 return manifest()->IsHostedApp(); | 506 return manifest()->IsHostedApp(); |
| 484 } | 507 } |
| 485 | 508 |
| 486 bool Extension::is_packaged_app() const { | 509 bool Extension::is_packaged_app() const { |
| 487 return manifest()->IsPackagedApp(); | 510 return manifest()->IsPackagedApp(); |
| 488 } | 511 } |
| 489 | 512 |
| 490 bool Extension::is_theme() const { | 513 bool Extension::is_theme() const { |
| 491 return manifest()->IsTheme(); | 514 return manifest()->IsTheme(); |
| 492 } | 515 } |
| 493 | 516 |
| 494 GURL Extension::GetBackgroundURL() const { | 517 GURL Extension::GetBackgroundURL() const { |
| 495 if (!background_scripts_.empty()) { | 518 if (!background_scripts_.empty()) { |
| 496 return GetResourceURL( | 519 return GetResourceURL( |
| 497 extension_filenames::kGeneratedBackgroundPageFilename); | 520 extension_filenames::kGeneratedBackgroundPageFilename); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 528 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash))); | 551 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash))); |
| 529 ConvertHexadecimalToIDAlphabet(output); | 552 ConvertHexadecimalToIDAlphabet(output); |
| 530 | 553 |
| 531 return true; | 554 return true; |
| 532 } | 555 } |
| 533 | 556 |
| 534 // Helper method that loads a UserScript object from a dictionary in the | 557 // Helper method that loads a UserScript object from a dictionary in the |
| 535 // content_script list of the manifest. | 558 // content_script list of the manifest. |
| 536 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, | 559 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, |
| 537 int definition_index, | 560 int definition_index, |
| 538 int flags, | |
| 539 string16* error, | 561 string16* error, |
| 540 UserScript* result) { | 562 UserScript* result) { |
| 541 // run_at | 563 // run_at |
| 542 if (content_script->HasKey(keys::kRunAt)) { | 564 if (content_script->HasKey(keys::kRunAt)) { |
| 543 std::string run_location; | 565 std::string run_location; |
| 544 if (!content_script->GetString(keys::kRunAt, &run_location)) { | 566 if (!content_script->GetString(keys::kRunAt, &run_location)) { |
| 545 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 567 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 546 errors::kInvalidRunAt, | 568 errors::kInvalidRunAt, |
| 547 base::IntToString(definition_index)); | 569 base::IntToString(definition_index)); |
| 548 return false; | 570 return false; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 609 errors::kInvalidMatch, | 631 errors::kInvalidMatch, |
| 610 base::IntToString(definition_index), | 632 base::IntToString(definition_index), |
| 611 base::IntToString(j), | 633 base::IntToString(j), |
| 612 URLPattern::GetParseResultString(parse_result)); | 634 URLPattern::GetParseResultString(parse_result)); |
| 613 return false; | 635 return false; |
| 614 } | 636 } |
| 615 | 637 |
| 616 if (pattern.MatchesScheme(chrome::kFileScheme) && | 638 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 617 !CanExecuteScriptEverywhere()) { | 639 !CanExecuteScriptEverywhere()) { |
| 618 wants_file_access_ = true; | 640 wants_file_access_ = true; |
| 619 if (!(flags & ALLOW_FILE_ACCESS)) | 641 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) |
| 620 pattern.SetValidSchemes( | 642 pattern.SetValidSchemes( |
| 621 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 643 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 622 } | 644 } |
| 623 | 645 |
| 624 result->add_url_pattern(pattern); | 646 result->add_url_pattern(pattern); |
| 625 } | 647 } |
| 626 | 648 |
| 627 // exclude_matches | 649 // exclude_matches |
| 628 if (content_script->HasKey(keys::kExcludeMatches)) { // optional | 650 if (content_script->HasKey(keys::kExcludeMatches)) { // optional |
| 629 ListValue* exclude_matches = NULL; | 651 ListValue* exclude_matches = NULL; |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 885 result->SetPopupUrl(ExtensionAction::kDefaultTabId, url); | 907 result->SetPopupUrl(ExtensionAction::kDefaultTabId, url); |
| 886 } else { | 908 } else { |
| 887 DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId)) | 909 DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId)) |
| 888 << "Shouldn't be possible for the popup to be set."; | 910 << "Shouldn't be possible for the popup to be set."; |
| 889 } | 911 } |
| 890 } | 912 } |
| 891 | 913 |
| 892 return result.release(); | 914 return result.release(); |
| 893 } | 915 } |
| 894 | 916 |
| 895 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlers( | 917 // static |
| 896 const ListValue* extension_actions, string16* error) { | 918 bool Extension::InitExtensionID(extensions::Manifest* manifest, |
| 897 scoped_ptr<FileBrowserHandlerList> result( | 919 const FilePath& path, |
| 898 new FileBrowserHandlerList()); | 920 const std::string& explicit_id, |
| 899 for (ListValue::const_iterator iter = extension_actions->begin(); | 921 int creation_flags, |
| 900 iter != extension_actions->end(); | 922 string16* error) { |
| 901 ++iter) { | 923 if (!explicit_id.empty()) { |
| 902 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) { | 924 manifest->set_extension_id(explicit_id); |
| 903 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | 925 return true; |
| 904 return NULL; | 926 } |
| 927 | |
| 928 if (manifest->HasKey(keys::kPublicKey)) { | |
| 929 std::string public_key; | |
| 930 std::string public_key_bytes; | |
| 931 std::string extension_id; | |
| 932 if (!manifest->GetString(keys::kPublicKey, &public_key) || | |
| 933 !ParsePEMKeyBytes(public_key, &public_key_bytes) || | |
| 934 !GenerateId(public_key_bytes, &extension_id)) { | |
| 935 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 936 return false; | |
| 905 } | 937 } |
| 906 scoped_ptr<FileBrowserHandler> action( | 938 manifest->set_extension_id(extension_id); |
| 907 LoadFileBrowserHandler( | 939 return true; |
| 908 reinterpret_cast<DictionaryValue*>(*iter), error)); | |
| 909 if (!action.get()) | |
| 910 return NULL; // Failed to parse file browser action definition. | |
| 911 result->push_back(linked_ptr<FileBrowserHandler>(action.release())); | |
| 912 } | 940 } |
| 913 return result.release(); | 941 |
| 942 if (creation_flags & REQUIRE_KEY) { | |
| 943 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 944 return false; | |
| 945 } else { | |
| 946 // If there is a path, we generate the ID from it. This is useful for | |
| 947 // development mode, because it keeps the ID stable across restarts and | |
| 948 // reloading the extension. | |
| 949 std::string extension_id = GenerateIdForPath(path); | |
| 950 if (extension_id.empty()) { | |
| 951 NOTREACHED() << "Could not create ID from path."; | |
| 952 return false; | |
| 953 } | |
| 954 manifest->set_extension_id(extension_id); | |
| 955 return true; | |
| 956 } | |
| 914 } | 957 } |
| 915 | 958 |
| 916 FileBrowserHandler* Extension::LoadFileBrowserHandler( | 959 bool Extension::CheckMinimumChromeVersion(string16* error) { |
| 917 const DictionaryValue* file_browser_handler, string16* error) { | 960 if (!manifest_->HasKey(keys::kMinimumChromeVersion)) |
| 918 scoped_ptr<FileBrowserHandler> result( | 961 return true; |
| 919 new FileBrowserHandler()); | 962 std::string minimum_version_string; |
| 920 result->set_extension_id(id()); | 963 if (!manifest_->GetString(keys::kMinimumChromeVersion, |
| 921 | 964 &minimum_version_string)) { |
| 922 std::string id; | 965 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); |
| 923 // Read the file action |id| (mandatory). | 966 return false; |
| 924 if (!file_browser_handler->HasKey(keys::kPageActionId) || | |
| 925 !file_browser_handler->GetString(keys::kPageActionId, &id)) { | |
| 926 *error = ASCIIToUTF16(errors::kInvalidPageActionId); | |
| 927 return NULL; | |
| 928 } | |
| 929 result->set_id(id); | |
| 930 | |
| 931 // Read the page action title from |default_title| (mandatory). | |
| 932 std::string title; | |
| 933 if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) || | |
| 934 !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) { | |
| 935 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); | |
| 936 return NULL; | |
| 937 } | |
| 938 result->set_title(title); | |
| 939 | |
| 940 // Initialize file filters (mandatory). | |
| 941 ListValue* list_value = NULL; | |
| 942 if (!file_browser_handler->HasKey(keys::kFileFilters) || | |
| 943 !file_browser_handler->GetList(keys::kFileFilters, &list_value) || | |
| 944 list_value->empty()) { | |
| 945 *error = ASCIIToUTF16(errors::kInvalidFileFiltersList); | |
| 946 return NULL; | |
| 947 } | |
| 948 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 949 std::string filter; | |
| 950 if (!list_value->GetString(i, &filter)) { | |
| 951 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 952 errors::kInvalidFileFilterValue, base::IntToString(i)); | |
| 953 return NULL; | |
| 954 } | |
| 955 StringToLowerASCII(&filter); | |
| 956 URLPattern pattern(URLPattern::SCHEME_FILESYSTEM); | |
| 957 if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) { | |
| 958 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 959 errors::kInvalidURLPatternError, filter); | |
| 960 return NULL; | |
| 961 } | |
| 962 std::string path = pattern.path(); | |
| 963 bool allowed = path == "*" || path == "*.*" || | |
| 964 (path.compare(0, 2, "*.") == 0 && | |
| 965 path.find_first_of('*', 2) == std::string::npos); | |
| 966 if (!allowed) { | |
| 967 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 968 errors::kInvalidURLPatternError, filter); | |
| 969 return NULL; | |
| 970 } | |
| 971 result->AddPattern(pattern); | |
| 972 } | 967 } |
| 973 | 968 |
| 974 std::string default_icon; | 969 scoped_ptr<Version> minimum_version( |
| 975 // Read the file browser action |default_icon| (optional). | 970 Version::GetVersionFromString(minimum_version_string)); |
| 976 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { | 971 if (!minimum_version.get()) { |
| 977 if (!file_browser_handler->GetString( | 972 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); |
| 978 keys::kPageActionDefaultIcon, &default_icon) || | 973 return false; |
| 979 default_icon.empty()) { | |
| 980 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | |
| 981 return NULL; | |
| 982 } | |
| 983 result->set_icon_path(default_icon); | |
| 984 } | 974 } |
| 985 | 975 |
| 986 return result.release(); | 976 chrome::VersionInfo current_version_info; |
| 977 if (!current_version_info.is_valid()) { | |
| 978 NOTREACHED(); | |
| 979 return false; | |
| 980 } | |
| 981 | |
| 982 scoped_ptr<Version> current_version( | |
| 983 Version::GetVersionFromString(current_version_info.Version())); | |
| 984 if (!current_version.get()) { | |
| 985 DCHECK(false); | |
| 986 return false; | |
| 987 } | |
| 988 | |
| 989 if (current_version->CompareTo(*minimum_version) < 0) { | |
| 990 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 991 errors::kChromeVersionTooLow, | |
| 992 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME), | |
| 993 minimum_version_string); | |
| 994 return false; | |
| 995 } | |
| 996 return true; | |
| 997 } | |
| 998 | |
| 999 bool Extension::LoadRequiredFeatures(string16* error) { | |
| 1000 if (!LoadName(error) || | |
| 1001 !LoadVersion(error)) | |
| 1002 return false; | |
| 1003 return true; | |
| 1004 } | |
| 1005 | |
| 1006 bool Extension::LoadName(string16* error) { | |
| 1007 string16 localized_name; | |
| 1008 if (!manifest_->GetString(keys::kName, &localized_name)) { | |
| 1009 *error = ASCIIToUTF16(errors::kInvalidName); | |
| 1010 return false; | |
| 1011 } | |
| 1012 base::i18n::AdjustStringForLocaleDirection(&localized_name); | |
| 1013 name_ = UTF16ToUTF8(localized_name); | |
| 1014 return true; | |
| 1015 } | |
| 1016 | |
| 1017 bool Extension::LoadDescription(string16* error) { | |
| 1018 if (manifest_->HasKey(keys::kDescription) && | |
| 1019 !manifest_->GetString(keys::kDescription, &description_)) { | |
| 1020 *error = ASCIIToUTF16(errors::kInvalidDescription); | |
| 1021 return false; | |
| 1022 } | |
| 1023 return true; | |
| 1024 } | |
| 1025 | |
| 1026 bool Extension::LoadAppFeatures(string16* error) { | |
| 1027 if (!LoadExtent(keys::kWebURLs, &extent_, | |
| 1028 errors::kInvalidWebURLs, errors::kInvalidWebURL, error) || | |
| 1029 !LoadLaunchURL(error) || | |
| 1030 !LoadLaunchContainer(error)) | |
| 1031 return false; | |
| 1032 | |
| 1033 return true; | |
| 987 } | 1034 } |
| 988 | 1035 |
| 989 bool Extension::LoadExtent(const char* key, | 1036 bool Extension::LoadExtent(const char* key, |
| 990 URLPatternSet* extent, | 1037 URLPatternSet* extent, |
| 991 const char* list_error, | 1038 const char* list_error, |
| 992 const char* value_error, | 1039 const char* value_error, |
| 993 string16* error) { | 1040 string16* error) { |
| 994 Value* temp = NULL; | 1041 Value* temp = NULL; |
| 995 if (!manifest_->Get(key, &temp)) | 1042 if (!manifest_->Get(key, &temp)) |
| 996 return true; | 1043 return true; |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1157 if (!cloud_print_service_url.is_empty()) { | 1204 if (!cloud_print_service_url.is_empty()) { |
| 1158 std::string path( | 1205 std::string path( |
| 1159 cloud_print_service_url.path() + "/enable_chrome_connector"); | 1206 cloud_print_service_url.path() + "/enable_chrome_connector"); |
| 1160 GURL::Replacements replacements; | 1207 GURL::Replacements replacements; |
| 1161 replacements.SetPathStr(path); | 1208 replacements.SetPathStr(path); |
| 1162 GURL cloud_print_enable_connector_url = | 1209 GURL cloud_print_enable_connector_url = |
| 1163 cloud_print_service_url.ReplaceComponents(replacements); | 1210 cloud_print_service_url.ReplaceComponents(replacements); |
| 1164 OverrideLaunchUrl(cloud_print_enable_connector_url); | 1211 OverrideLaunchUrl(cloud_print_enable_connector_url); |
| 1165 } | 1212 } |
| 1166 } | 1213 } |
| 1214 | |
| 1167 return true; | 1215 return true; |
| 1168 } | 1216 } |
| 1169 | 1217 |
| 1170 bool ReadLaunchDimension(const extensions::Manifest* manifest, | |
| 1171 const char* key, | |
| 1172 int* target, | |
| 1173 bool is_valid_container, | |
| 1174 string16* error) { | |
| 1175 Value* temp = NULL; | |
| 1176 if (manifest->Get(key, &temp)) { | |
| 1177 if (!is_valid_container) { | |
| 1178 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1179 errors::kInvalidLaunchValueContainer, | |
| 1180 key); | |
| 1181 return false; | |
| 1182 } | |
| 1183 if (!temp->GetAsInteger(target) || *target < 0) { | |
| 1184 *target = 0; | |
| 1185 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1186 errors::kInvalidLaunchValue, | |
| 1187 key); | |
| 1188 return false; | |
| 1189 } | |
| 1190 } | |
| 1191 return true; | |
| 1192 } | |
| 1193 | |
| 1194 bool Extension::LoadLaunchContainer(string16* error) { | 1218 bool Extension::LoadLaunchContainer(string16* error) { |
| 1195 Value* temp = NULL; | 1219 Value* temp = NULL; |
| 1196 if (!manifest_->Get(keys::kLaunchContainer, &temp)) | 1220 if (!manifest_->Get(keys::kLaunchContainer, &temp)) |
| 1197 return true; | 1221 return true; |
| 1198 | 1222 |
| 1199 std::string launch_container_string; | 1223 std::string launch_container_string; |
| 1200 if (!temp->GetAsString(&launch_container_string)) { | 1224 if (!temp->GetAsString(&launch_container_string)) { |
| 1201 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer); | 1225 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer); |
| 1202 return false; | 1226 return false; |
| 1203 } | 1227 } |
| 1204 | 1228 |
| 1205 if (launch_container_string == values::kLaunchContainerShell) { | 1229 if (launch_container_string == values::kLaunchContainerShell) { |
| 1206 launch_container_ = extension_misc::LAUNCH_SHELL; | 1230 launch_container_ = extension_misc::LAUNCH_SHELL; |
| 1207 } else if (launch_container_string == values::kLaunchContainerPanel) { | 1231 } else if (launch_container_string == values::kLaunchContainerPanel) { |
| 1208 launch_container_ = extension_misc::LAUNCH_PANEL; | 1232 launch_container_ = extension_misc::LAUNCH_PANEL; |
| 1209 } else if (launch_container_string == values::kLaunchContainerTab) { | 1233 } else if (launch_container_string == values::kLaunchContainerTab) { |
| 1210 launch_container_ = extension_misc::LAUNCH_TAB; | 1234 launch_container_ = extension_misc::LAUNCH_TAB; |
| 1211 } else { | 1235 } else { |
| 1212 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer); | 1236 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer); |
| 1213 return false; | 1237 return false; |
| 1214 } | 1238 } |
| 1215 | 1239 |
| 1216 bool can_specify_initial_size = | 1240 bool can_specify_initial_size = |
| 1217 launch_container() == extension_misc::LAUNCH_PANEL || | 1241 launch_container_ == extension_misc::LAUNCH_PANEL || |
| 1218 launch_container() == extension_misc::LAUNCH_WINDOW || | 1242 launch_container_ == extension_misc::LAUNCH_WINDOW || |
| 1219 launch_container() == extension_misc::LAUNCH_SHELL; | 1243 launch_container_ == extension_misc::LAUNCH_SHELL; |
| 1220 | 1244 |
| 1221 // Validate the container width if present. | 1245 // Validate the container width if present. |
| 1222 if (!ReadLaunchDimension(manifest_, | 1246 if (!ReadLaunchDimension(manifest_, |
| 1223 keys::kLaunchWidth, | 1247 keys::kLaunchWidth, |
| 1224 &launch_width_, | 1248 &launch_width_, |
| 1225 can_specify_initial_size, | 1249 can_specify_initial_size, |
| 1226 error)) | 1250 error)) |
| 1227 return false; | 1251 return false; |
| 1228 | 1252 |
| 1229 // Validate container height if present. | 1253 // Validate container height if present. |
| 1230 if (!ReadLaunchDimension(manifest_, | 1254 if (!ReadLaunchDimension(manifest_, |
| 1231 keys::kLaunchHeight, | 1255 keys::kLaunchHeight, |
| 1232 &launch_height_, | 1256 &launch_height_, |
| 1233 can_specify_initial_size, | 1257 can_specify_initial_size, |
| 1234 error)) | 1258 error)) |
| 1235 return false; | 1259 return false; |
| 1236 | 1260 |
| 1237 bool can_specify_size_range = | 1261 bool can_specify_size_range = |
| 1238 launch_container() == extension_misc::LAUNCH_SHELL; | 1262 launch_container_ == extension_misc::LAUNCH_SHELL; |
| 1239 | 1263 |
| 1240 // Validate min size if present. | 1264 // Validate min size if present. |
| 1241 if (!ReadLaunchDimension(manifest_, | 1265 if (!ReadLaunchDimension(manifest_, |
| 1242 keys::kLaunchMinWidth, | 1266 keys::kLaunchMinWidth, |
| 1243 &launch_min_width_, | 1267 &launch_min_width_, |
| 1244 can_specify_size_range, | 1268 can_specify_size_range, |
| 1245 error)) | 1269 error)) |
| 1246 return false; | 1270 return false; |
| 1247 if (!ReadLaunchDimension(manifest_, | 1271 if (!ReadLaunchDimension(manifest_, |
| 1248 keys::kLaunchMinHeight, | 1272 keys::kLaunchMinHeight, |
| 1249 &launch_min_height_, | 1273 &launch_min_height_, |
| 1250 can_specify_size_range, | 1274 can_specify_size_range, |
| 1251 error)) | 1275 error)) |
| 1252 return false; | 1276 return false; |
| 1253 if (!ReadLaunchDimension(manifest_, | 1277 if (!ReadLaunchDimension(manifest_, |
| 1254 keys::kLaunchMaxWidth, | 1278 keys::kLaunchMaxWidth, |
| 1255 &launch_max_width_, | 1279 &launch_max_width_, |
| 1256 can_specify_size_range, | 1280 can_specify_size_range, |
| 1257 error)) | 1281 error)) |
| 1258 return false; | 1282 return false; |
| 1259 if (!ReadLaunchDimension(manifest_, | 1283 if (!ReadLaunchDimension(manifest_, |
| 1260 keys::kLaunchMaxHeight, | 1284 keys::kLaunchMaxHeight, |
| 1261 &launch_max_height_, | 1285 &launch_max_height_, |
| 1262 can_specify_size_range, | 1286 can_specify_size_range, |
| 1263 error)) | 1287 error)) |
| 1264 return false; | 1288 return false; |
| 1265 | 1289 |
| 1266 if (launch_container() == extension_misc::LAUNCH_SHELL) { | 1290 if (launch_container_ == extension_misc::LAUNCH_SHELL) { |
| 1267 if (!manifest_->Get(keys::kLaunchWidth, &temp)) { | 1291 if (!manifest_->Get(keys::kLaunchWidth, &temp)) { |
| 1268 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1292 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1269 errors::kInvalidLaunchValue, | 1293 errors::kInvalidLaunchValue, |
| 1270 keys::kLaunchWidth); | 1294 keys::kLaunchWidth); |
| 1271 return false; | 1295 return false; |
| 1272 } | 1296 } |
| 1273 if (!manifest_->Get(keys::kLaunchHeight, &temp)) { | 1297 if (!manifest_->Get(keys::kLaunchHeight, &temp)) { |
| 1274 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1298 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1275 errors::kInvalidLaunchValue, | 1299 errors::kInvalidLaunchValue, |
| 1276 keys::kLaunchHeight); | 1300 keys::kLaunchHeight); |
| 1277 return false; | 1301 return false; |
| 1278 } | 1302 } |
| 1279 if (launch_max_width_ > 0 && launch_max_width_ < launch_min_width_) { | 1303 if (launch_max_width_ > 0 && launch_max_width_ < launch_min_width_) { |
| 1280 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1304 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1281 errors::kInvalidLaunchValue, | 1305 errors::kInvalidLaunchValue, |
| 1282 keys::kLaunchMaxWidth); | 1306 keys::kLaunchMaxWidth); |
| 1283 return false; | 1307 return false; |
| 1284 } | 1308 } |
| 1285 if (launch_max_height_ > 0 && launch_max_height_ < launch_min_height_) { | 1309 if (launch_max_height_ > 0 && launch_max_height_ < launch_min_height_) { |
| 1286 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1310 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1287 errors::kInvalidLaunchValue, | 1311 errors::kInvalidLaunchValue, |
| 1288 keys::kLaunchMaxHeight); | 1312 keys::kLaunchMaxHeight); |
| 1289 return false; | 1313 return false; |
| 1290 } | 1314 } |
| 1291 } | 1315 } |
| 1292 | 1316 |
| 1293 return true; | 1317 if (is_platform_app()) { |
| 1294 } | 1318 if (launch_container_ != extension_misc::LAUNCH_SHELL) { |
| 1295 | 1319 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform); |
| 1296 bool Extension::LoadAppIsolation(string16* error) { | 1320 return false; |
| 1297 Value* temp = NULL; | 1321 } |
| 1298 if (!manifest_->Get(keys::kIsolation, &temp)) | 1322 } else if (launch_container_ == extension_misc::LAUNCH_SHELL) { |
| 1299 return true; | 1323 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform); |
| 1300 | 1324 return false; |
| 1301 if (temp->GetType() != Value::TYPE_LIST) { | 1325 } |
| 1302 *error = ASCIIToUTF16(errors::kInvalidIsolation); | 1326 |
| 1303 return false; | 1327 return true; |
| 1304 } | 1328 } |
| 1305 | 1329 |
| 1306 ListValue* isolation_list = static_cast<ListValue*>(temp); | 1330 bool Extension::LoadSharedFeatures( |
| 1307 for (size_t i = 0; i < isolation_list->GetSize(); ++i) { | 1331 const ExtensionAPIPermissionSet& api_permissions, |
| 1308 std::string isolation_string; | 1332 string16* error) { |
| 1309 if (!isolation_list->GetString(i, &isolation_string)) { | 1333 if (!LoadDescription(error) || |
|
Aaron Boodman
2012/03/07 21:10:54
So pretty.
| |
| 1310 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1334 !LoadManifestVersion(error) || |
| 1311 errors::kInvalidIsolationValue, | 1335 !LoadHomepageURL(error) || |
| 1312 base::UintToString(i)); | 1336 !LoadUpdateURL(error) || |
| 1313 return false; | 1337 !LoadIcons(error) || |
| 1314 } | 1338 !LoadCommands(error) || |
| 1315 | 1339 !LoadPlugins(error) || |
| 1316 // Check for isolated storage. | 1340 !LoadNaClModules(error) || |
| 1317 if (isolation_string == values::kIsolatedStorage) { | 1341 !LoadWebAccessibleResources(error) || |
| 1318 is_storage_isolated_ = true; | 1342 !CheckRequirements(error) || |
| 1319 } else { | 1343 !LoadDefaultLocale(error) || |
| 1320 DLOG(WARNING) << "Did not recognize isolation type: " | 1344 !LoadOfflineEnabled(error) || |
| 1321 << isolation_string; | 1345 !LoadOptionsPage(error) || |
| 1322 } | 1346 // LoadBackgroundScripts() must be called before LoadBackgroundPage(). |
| 1323 } | 1347 !LoadBackgroundScripts(error) || |
| 1324 return true; | 1348 !LoadBackgroundPage(api_permissions, error) || |
| 1325 } | 1349 !LoadBackgroundPersistent(api_permissions, error) || |
| 1326 | 1350 !LoadBackgroundAllowJsAccess(api_permissions, error) || |
| 1327 bool Extension::LoadWebIntentServices(string16* error) { | 1351 !LoadWebIntentServices(error)) |
| 1328 DCHECK(error); | 1352 return false; |
| 1329 | 1353 |
| 1330 if (!manifest_->HasKey(keys::kIntents)) | 1354 return true; |
| 1331 return true; | 1355 } |
| 1332 | 1356 |
| 1333 DictionaryValue* all_services = NULL; | 1357 bool Extension::LoadVersion(string16* error) { |
| 1334 if (!manifest_->GetDictionary(keys::kIntents, &all_services)) { | 1358 std::string version_str; |
| 1335 *error = ASCIIToUTF16(errors::kInvalidIntents); | 1359 if (!manifest_->GetString(keys::kVersion, &version_str)) { |
| 1336 return false; | 1360 *error = ASCIIToUTF16(errors::kInvalidVersion); |
| 1337 } | 1361 return false; |
| 1338 | 1362 } |
| 1339 std::string value; | 1363 version_.reset(Version::GetVersionFromString(version_str)); |
| 1340 for (DictionaryValue::key_iterator iter(all_services->begin_keys()); | 1364 if (!version_.get() || |
| 1341 iter != all_services->end_keys(); ++iter) { | 1365 version_->components().size() > 4) { |
| 1342 webkit_glue::WebIntentServiceData service; | 1366 *error = ASCIIToUTF16(errors::kInvalidVersion); |
| 1343 | 1367 return false; |
| 1344 DictionaryValue* one_service = NULL; | 1368 } |
| 1345 if (!all_services->GetDictionaryWithoutPathExpansion(*iter, &one_service)) { | 1369 return true; |
| 1346 *error = ASCIIToUTF16(errors::kInvalidIntent); | 1370 } |
| 1347 return false; | 1371 |
| 1348 } | 1372 bool Extension::LoadManifestVersion(string16* error) { |
| 1349 service.action = UTF8ToUTF16(*iter); | 1373 // Get the original value out of the dictionary so that we can validate it |
| 1350 | 1374 // more strictly. |
| 1351 ListValue* mime_types = NULL; | 1375 if (manifest_->value()->HasKey(keys::kManifestVersion)) { |
| 1352 if (!one_service->HasKey(keys::kIntentType) || | 1376 int manifest_version = 1; |
| 1353 !one_service->GetList(keys::kIntentType, &mime_types) || | 1377 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) || |
| 1354 mime_types->GetSize() == 0) { | 1378 manifest_version < 1) { |
| 1355 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1379 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); |
| 1356 errors::kInvalidIntentType, *iter); | 1380 return false; |
| 1357 return false; | 1381 } |
| 1358 } | 1382 } |
| 1359 | 1383 |
| 1360 if (one_service->HasKey(keys::kIntentPath)) { | 1384 manifest_version_ = manifest_->GetManifestVersion(); |
| 1361 if (!one_service->GetString(keys::kIntentPath, &value)) { | 1385 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION && |
| 1362 *error = ASCIIToUTF16(errors::kInvalidIntentPath); | 1386 manifest_version_ < kModernManifestVersion && |
| 1387 !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1388 switches::kAllowLegacyExtensionManifests)) { | |
| 1389 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1390 return false; | |
| 1391 } | |
| 1392 | |
| 1393 return true; | |
| 1394 } | |
| 1395 | |
| 1396 bool Extension::LoadHomepageURL(string16* error) { | |
| 1397 if (!manifest_->HasKey(keys::kHomepageURL)) | |
| 1398 return true; | |
| 1399 std::string tmp; | |
| 1400 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) { | |
| 1401 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1402 errors::kInvalidHomepageURL, ""); | |
| 1403 return false; | |
| 1404 } | |
| 1405 homepage_url_ = GURL(tmp); | |
| 1406 if (!homepage_url_.is_valid() || | |
| 1407 (!homepage_url_.SchemeIs("http") && | |
| 1408 !homepage_url_.SchemeIs("https"))) { | |
| 1409 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1410 errors::kInvalidHomepageURL, tmp); | |
| 1411 return false; | |
| 1412 } | |
| 1413 return true; | |
| 1414 } | |
| 1415 | |
| 1416 bool Extension::LoadUpdateURL(string16* error) { | |
| 1417 if (!manifest_->HasKey(keys::kUpdateURL)) | |
| 1418 return true; | |
| 1419 std::string tmp; | |
| 1420 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) { | |
| 1421 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1422 errors::kInvalidUpdateURL, ""); | |
| 1423 return false; | |
| 1424 } | |
| 1425 update_url_ = GURL(tmp); | |
| 1426 if (!update_url_.is_valid() || | |
| 1427 update_url_.has_ref()) { | |
| 1428 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1429 errors::kInvalidUpdateURL, tmp); | |
| 1430 return false; | |
| 1431 } | |
| 1432 return true; | |
| 1433 } | |
| 1434 | |
| 1435 bool Extension::LoadIcons(string16* error) { | |
| 1436 if (!manifest_->HasKey(keys::kIcons)) | |
| 1437 return true; | |
| 1438 DictionaryValue* icons_value = NULL; | |
| 1439 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) { | |
| 1440 *error = ASCIIToUTF16(errors::kInvalidIcons); | |
| 1441 return false; | |
| 1442 } | |
| 1443 | |
| 1444 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) { | |
| 1445 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]); | |
| 1446 if (icons_value->HasKey(key)) { | |
| 1447 std::string icon_path; | |
| 1448 if (!icons_value->GetString(key, &icon_path)) { | |
| 1449 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1450 errors::kInvalidIconPath, key); | |
| 1363 return false; | 1451 return false; |
| 1364 } | 1452 } |
| 1365 if (is_hosted_app()) { | 1453 |
| 1366 // Hosted apps require an absolute URL for intents. | 1454 if (!icon_path.empty() && icon_path[0] == '/') |
| 1367 GURL service_url(value); | 1455 icon_path = icon_path.substr(1); |
| 1368 if (!service_url.is_valid() || | 1456 |
| 1369 !(web_extent().MatchesURL(service_url))) { | 1457 if (icon_path.empty()) { |
| 1370 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1458 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1371 errors::kInvalidIntentPageInHostedApp, *iter); | 1459 errors::kInvalidIconPath, key); |
| 1372 return false; | |
| 1373 } | |
| 1374 service.service_url = service_url; | |
| 1375 } else { | |
| 1376 // We do not allow absolute intent URLs in non-hosted apps. | |
| 1377 if (GURL(value).is_valid()) { | |
| 1378 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1379 errors::kCannotAccessPage, value.c_str()); | |
| 1380 return false; | |
| 1381 } | |
| 1382 service.service_url = GetResourceURL(value); | |
| 1383 } | |
| 1384 } | |
| 1385 | |
| 1386 if (one_service->HasKey(keys::kIntentTitle) && | |
| 1387 !one_service->GetString(keys::kIntentTitle, &service.title)) { | |
| 1388 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | |
| 1389 return false; | |
| 1390 } | |
| 1391 | |
| 1392 if (one_service->HasKey(keys::kIntentDisposition)) { | |
| 1393 if (!one_service->GetString(keys::kIntentDisposition, &value) || | |
| 1394 (value != values::kIntentDispositionWindow && | |
| 1395 value != values::kIntentDispositionInline)) { | |
| 1396 *error = ASCIIToUTF16(errors::kInvalidIntentDisposition); | |
| 1397 return false; | 1460 return false; |
| 1398 } | 1461 } |
| 1399 if (value == values::kIntentDispositionInline) { | 1462 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path); |
| 1400 service.disposition = | 1463 } |
| 1401 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; | 1464 } |
| 1402 } else { | 1465 return true; |
| 1403 service.disposition = | 1466 } |
| 1404 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW; | 1467 |
| 1405 } | 1468 bool Extension::LoadCommands(string16* error) { |
| 1406 } | 1469 if (manifest_->HasKey(keys::kCommands)) { |
| 1407 | 1470 DictionaryValue* commands = NULL; |
| 1408 for (size_t i = 0; i < mime_types->GetSize(); ++i) { | 1471 if (!manifest_->GetDictionary(keys::kCommands, &commands)) { |
| 1409 if (!mime_types->GetString(i, &service.type)) { | 1472 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); |
| 1473 return false; | |
| 1474 } | |
| 1475 | |
| 1476 int command_index = 0; | |
| 1477 for (DictionaryValue::key_iterator iter = commands->begin_keys(); | |
| 1478 iter != commands->end_keys(); ++iter) { | |
| 1479 ++command_index; | |
| 1480 | |
| 1481 DictionaryValue* command = NULL; | |
| 1482 if (!commands->GetDictionary(*iter, &command)) { | |
| 1410 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1483 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1411 errors::kInvalidIntentTypeElement, *iter, | 1484 errors::kInvalidKeyBindingDictionary, |
| 1412 std::string(base::IntToString(i))); | 1485 base::IntToString(command_index)); |
| 1413 return false; | 1486 return false; |
| 1414 } | 1487 } |
| 1415 intents_services_.push_back(service); | 1488 |
| 1416 } | 1489 ExtensionKeybinding binding; |
| 1417 } | 1490 if (!binding.Parse(command, *iter, command_index, error)) |
| 1418 return true; | 1491 return false; // |error| already set. |
| 1419 } | 1492 |
| 1420 | 1493 commands_.push_back(binding); |
| 1494 } | |
| 1495 } | |
| 1496 return true; | |
| 1497 } | |
| 1498 | |
| 1499 bool Extension::LoadPlugins(string16* error) { | |
| 1500 if (!manifest_->HasKey(keys::kPlugins)) | |
| 1501 return true; | |
| 1502 ListValue* list_value = NULL; | |
| 1503 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | |
| 1504 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 1505 return false; | |
| 1506 } | |
| 1507 | |
| 1508 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1509 DictionaryValue* plugin_value = NULL; | |
| 1510 std::string path_str; | |
| 1511 bool is_public = false; | |
| 1512 if (!list_value->GetDictionary(i, &plugin_value)) { | |
| 1513 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 1514 return false; | |
| 1515 } | |
| 1516 // Get plugins[i].path. | |
| 1517 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) { | |
| 1518 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1519 errors::kInvalidPluginsPath, base::IntToString(i)); | |
| 1520 return false; | |
| 1521 } | |
| 1522 | |
| 1523 // Get plugins[i].content (optional). | |
| 1524 if (plugin_value->HasKey(keys::kPluginsPublic)) { | |
| 1525 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) { | |
| 1526 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1527 errors::kInvalidPluginsPublic, base::IntToString(i)); | |
| 1528 return false; | |
| 1529 } | |
| 1530 } | |
| 1531 | |
| 1532 // We don't allow extension plugins to run on Chrome OS. We still | |
| 1533 // parse the manifest entry so that error messages are consistently | |
| 1534 // displayed across platforms. | |
| 1535 #if !defined(OS_CHROMEOS) | |
| 1536 plugins_.push_back(PluginInfo()); | |
| 1537 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str)); | |
| 1538 plugins_.back().is_public = is_public; | |
| 1539 #endif | |
| 1540 } | |
| 1541 return true; | |
| 1542 } | |
| 1543 | |
| 1544 bool Extension::LoadNaClModules(string16* error) { | |
| 1545 if (!manifest_->HasKey(keys::kNaClModules)) | |
| 1546 return true; | |
| 1547 ListValue* list_value = NULL; | |
| 1548 if (!manifest_->GetList(keys::kNaClModules, &list_value)) { | |
| 1549 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 1550 return false; | |
| 1551 } | |
| 1552 | |
| 1553 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1554 DictionaryValue* module_value = NULL; | |
| 1555 std::string path_str; | |
| 1556 std::string mime_type; | |
| 1557 | |
| 1558 if (!list_value->GetDictionary(i, &module_value)) { | |
| 1559 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 1560 return false; | |
| 1561 } | |
| 1562 | |
| 1563 // Get nacl_modules[i].path. | |
| 1564 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) { | |
| 1565 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1566 errors::kInvalidNaClModulesPath, base::IntToString(i)); | |
| 1567 return false; | |
| 1568 } | |
| 1569 | |
| 1570 // Get nacl_modules[i].mime_type. | |
| 1571 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) { | |
| 1572 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1573 errors::kInvalidNaClModulesMIMEType, base::IntToString(i)); | |
| 1574 return false; | |
| 1575 } | |
| 1576 | |
| 1577 nacl_modules_.push_back(NaClModuleInfo()); | |
| 1578 nacl_modules_.back().url = GetResourceURL(path_str); | |
| 1579 nacl_modules_.back().mime_type = mime_type; | |
| 1580 } | |
| 1581 | |
| 1582 return true; | |
| 1583 } | |
| 1584 | |
| 1585 bool Extension::LoadWebAccessibleResources(string16* error) { | |
| 1586 if (!manifest_->HasKey(keys::kWebAccessibleResources)) | |
| 1587 return true; | |
| 1588 ListValue* list_value; | |
| 1589 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) { | |
| 1590 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList); | |
| 1591 return false; | |
| 1592 } | |
| 1593 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1594 std::string relative_path; | |
| 1595 if (!list_value->GetString(i, &relative_path)) { | |
| 1596 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1597 errors::kInvalidWebAccessibleResource, base::IntToString(i)); | |
| 1598 return false; | |
| 1599 } | |
| 1600 if (relative_path[0] != '/') | |
| 1601 relative_path = '/' + relative_path; | |
| 1602 web_accessible_resources_.insert(relative_path); | |
| 1603 } | |
| 1604 | |
| 1605 return true; | |
| 1606 } | |
| 1607 | |
| 1608 // These are not actually persisted (they're only used by the store), but | |
| 1609 // still validated. | |
| 1610 bool Extension::CheckRequirements(string16* error) { | |
| 1611 if (!manifest_->HasKey(keys::kRequirements)) | |
| 1612 return true; | |
| 1613 DictionaryValue* requirements_value = NULL; | |
| 1614 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) { | |
| 1615 *error = ASCIIToUTF16(errors::kInvalidRequirements); | |
| 1616 return false; | |
| 1617 } | |
| 1618 | |
| 1619 for (DictionaryValue::key_iterator it = requirements_value->begin_keys(); | |
| 1620 it != requirements_value->end_keys(); ++it) { | |
| 1621 DictionaryValue* requirement_value; | |
| 1622 if (!requirements_value->GetDictionaryWithoutPathExpansion( | |
| 1623 *it, &requirement_value)) { | |
| 1624 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1625 errors::kInvalidRequirement, *it); | |
| 1626 return false; | |
| 1627 } | |
| 1628 } | |
| 1629 return true; | |
| 1630 } | |
| 1631 | |
| 1632 bool Extension::LoadDefaultLocale(string16* error) { | |
| 1633 if (!manifest_->HasKey(keys::kDefaultLocale)) | |
| 1634 return true; | |
| 1635 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) || | |
| 1636 !l10n_util::IsValidLocaleSyntax(default_locale_)) { | |
| 1637 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale); | |
| 1638 return false; | |
| 1639 } | |
| 1640 return true; | |
| 1641 } | |
| 1642 | |
| 1643 bool Extension::LoadOfflineEnabled(string16* error) { | |
| 1644 // Defaults to false. | |
| 1645 if (manifest_->HasKey(keys::kOfflineEnabled) && | |
| 1646 !manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { | |
| 1647 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled); | |
| 1648 return false; | |
| 1649 } | |
| 1650 return true; | |
| 1651 } | |
| 1652 | |
| 1653 bool Extension::LoadOptionsPage(string16* error) { | |
| 1654 if (!manifest_->HasKey(keys::kOptionsPage)) | |
| 1655 return true; | |
| 1656 std::string options_str; | |
| 1657 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) { | |
| 1658 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 1659 return false; | |
| 1660 } | |
| 1661 | |
| 1662 if (is_hosted_app()) { | |
| 1663 // hosted apps require an absolute URL. | |
| 1664 GURL options_url(options_str); | |
| 1665 if (!options_url.is_valid() || | |
| 1666 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) { | |
| 1667 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp); | |
| 1668 return false; | |
| 1669 } | |
| 1670 options_url_ = options_url; | |
| 1671 } else { | |
| 1672 GURL absolute(options_str); | |
| 1673 if (absolute.is_valid()) { | |
| 1674 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage); | |
| 1675 return false; | |
| 1676 } | |
| 1677 options_url_ = GetResourceURL(options_str); | |
| 1678 if (!options_url_.is_valid()) { | |
| 1679 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 1680 return false; | |
| 1681 } | |
| 1682 } | |
| 1683 | |
| 1684 return true; | |
| 1685 } | |
| 1686 | |
| 1421 bool Extension::LoadBackgroundScripts(string16* error) { | 1687 bool Extension::LoadBackgroundScripts(string16* error) { |
| 1422 Value* background_scripts_value = NULL; | 1688 Value* background_scripts_value = NULL; |
| 1423 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) | 1689 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) |
| 1424 return true; | 1690 return true; |
| 1425 | 1691 |
| 1426 CHECK(background_scripts_value); | 1692 CHECK(background_scripts_value); |
| 1427 if (background_scripts_value->GetType() != Value::TYPE_LIST) { | 1693 if (background_scripts_value->GetType() != Value::TYPE_LIST) { |
| 1428 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); | 1694 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); |
| 1429 return false; | 1695 return false; |
| 1430 } | 1696 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1508 } | 1774 } |
| 1509 | 1775 |
| 1510 if (!has_background_page()) { | 1776 if (!has_background_page()) { |
| 1511 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); | 1777 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); |
| 1512 return false; | 1778 return false; |
| 1513 } | 1779 } |
| 1514 | 1780 |
| 1515 return true; | 1781 return true; |
| 1516 } | 1782 } |
| 1517 | 1783 |
| 1518 bool Extension::LoadBackgroundAllowJsAccess( | 1784 bool Extension::LoadBackgroundAllowJsAccess( |
|
Aaron Boodman
2012/03/07 21:10:54
Nit: "JS" should be capitalized, or you could also
Devlin
2012/03/09 05:46:18
It's changed in the function name; I'll submit a m
| |
| 1519 const ExtensionAPIPermissionSet& api_permissions, | 1785 const ExtensionAPIPermissionSet& api_permissions, |
| 1520 string16* error) { | 1786 string16* error) { |
| 1521 Value* allow_js_access = NULL; | 1787 Value* allow_js_access = NULL; |
| 1522 if (!manifest_->Get(keys::kBackgroundAllowJsAccess, &allow_js_access)) | 1788 if (!manifest_->Get(keys::kBackgroundAllowJsAccess, &allow_js_access)) |
| 1523 return true; | 1789 return true; |
| 1524 | 1790 |
| 1525 if (!allow_js_access->IsType(Value::TYPE_BOOLEAN) || | 1791 if (!allow_js_access->IsType(Value::TYPE_BOOLEAN) || |
| 1526 !allow_js_access->GetAsBoolean(&allow_background_js_access_)) { | 1792 !allow_js_access->GetAsBoolean(&allow_background_js_access_)) { |
| 1527 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess); | 1793 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess); |
| 1528 return false; | 1794 return false; |
| 1529 } | 1795 } |
| 1530 | 1796 |
| 1531 if (!has_background_page()) { | 1797 if (!has_background_page()) { |
| 1532 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccessNoPage); | 1798 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccessNoPage); |
| 1533 return false; | 1799 return false; |
| 1534 } | 1800 } |
| 1535 | 1801 |
| 1536 return true; | 1802 return true; |
| 1537 } | 1803 } |
| 1538 | 1804 |
| 1805 bool Extension::LoadWebIntentServices(string16* error) { | |
| 1806 DCHECK(error); | |
| 1807 | |
| 1808 if (!manifest_->HasKey(keys::kIntents)) | |
| 1809 return true; | |
| 1810 | |
| 1811 DictionaryValue* all_services = NULL; | |
| 1812 if (!manifest_->GetDictionary(keys::kIntents, &all_services)) { | |
| 1813 *error = ASCIIToUTF16(errors::kInvalidIntents); | |
| 1814 return false; | |
| 1815 } | |
| 1816 | |
| 1817 std::string value; | |
| 1818 for (DictionaryValue::key_iterator iter(all_services->begin_keys()); | |
| 1819 iter != all_services->end_keys(); ++iter) { | |
| 1820 webkit_glue::WebIntentServiceData service; | |
| 1821 | |
| 1822 DictionaryValue* one_service = NULL; | |
| 1823 if (!all_services->GetDictionaryWithoutPathExpansion(*iter, &one_service)) { | |
| 1824 *error = ASCIIToUTF16(errors::kInvalidIntent); | |
| 1825 return false; | |
| 1826 } | |
| 1827 service.action = UTF8ToUTF16(*iter); | |
| 1828 | |
| 1829 ListValue* mime_types = NULL; | |
| 1830 if (!one_service->HasKey(keys::kIntentType) || | |
| 1831 !one_service->GetList(keys::kIntentType, &mime_types) || | |
| 1832 mime_types->GetSize() == 0) { | |
| 1833 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1834 errors::kInvalidIntentType, *iter); | |
| 1835 return false; | |
| 1836 } | |
| 1837 | |
| 1838 if (one_service->HasKey(keys::kIntentPath)) { | |
| 1839 if (!one_service->GetString(keys::kIntentPath, &value)) { | |
| 1840 *error = ASCIIToUTF16(errors::kInvalidIntentPath); | |
| 1841 return false; | |
| 1842 } | |
| 1843 if (is_hosted_app()) { | |
| 1844 // Hosted apps require an absolute URL for intents. | |
| 1845 GURL service_url(value); | |
| 1846 if (!service_url.is_valid() || | |
| 1847 !(web_extent().MatchesURL(service_url))) { | |
| 1848 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1849 errors::kInvalidIntentPageInHostedApp, *iter); | |
| 1850 return false; | |
| 1851 } | |
| 1852 service.service_url = service_url; | |
| 1853 } else { | |
| 1854 // We do not allow absolute intent URLs in non-hosted apps. | |
| 1855 if (GURL(value).is_valid()) { | |
| 1856 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1857 errors::kCannotAccessPage, value.c_str()); | |
| 1858 return false; | |
| 1859 } | |
| 1860 service.service_url = GetResourceURL(value); | |
| 1861 } | |
| 1862 } | |
| 1863 | |
| 1864 if (one_service->HasKey(keys::kIntentTitle) && | |
| 1865 !one_service->GetString(keys::kIntentTitle, &service.title)) { | |
| 1866 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | |
| 1867 return false; | |
| 1868 } | |
| 1869 | |
| 1870 if (one_service->HasKey(keys::kIntentDisposition)) { | |
| 1871 if (!one_service->GetString(keys::kIntentDisposition, &value) || | |
| 1872 (value != values::kIntentDispositionWindow && | |
| 1873 value != values::kIntentDispositionInline)) { | |
| 1874 *error = ASCIIToUTF16(errors::kInvalidIntentDisposition); | |
| 1875 return false; | |
| 1876 } | |
| 1877 if (value == values::kIntentDispositionInline) { | |
| 1878 service.disposition = | |
| 1879 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; | |
| 1880 } else { | |
| 1881 service.disposition = | |
| 1882 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW; | |
| 1883 } | |
| 1884 } | |
| 1885 | |
| 1886 for (size_t i = 0; i < mime_types->GetSize(); ++i) { | |
| 1887 if (!mime_types->GetString(i, &service.type)) { | |
| 1888 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1889 errors::kInvalidIntentTypeElement, *iter, | |
| 1890 std::string(base::IntToString(i))); | |
| 1891 return false; | |
| 1892 } | |
| 1893 intents_services_.push_back(service); | |
| 1894 } | |
| 1895 } | |
| 1896 return true; | |
| 1897 } | |
| 1898 | |
| 1899 bool Extension::LoadExtensionFeatures( | |
| 1900 const ExtensionAPIPermissionSet& api_permissions, | |
| 1901 string16* error) { | |
| 1902 if (manifest_->HasKey(keys::kConvertedFromUserScript)) | |
| 1903 manifest_->GetBoolean(keys::kConvertedFromUserScript, | |
| 1904 &converted_from_user_script_); | |
| 1905 | |
| 1906 if (!LoadDevToolsPage(error) || | |
| 1907 !LoadInputComponents(api_permissions, error) || | |
| 1908 !LoadContentScripts(error) || | |
| 1909 !LoadPageAction(error) || | |
| 1910 !LoadBrowserAction(error) || | |
| 1911 !LoadFileBrowserHandlers(error) || | |
| 1912 !LoadChromeURLOverrides(error) || | |
| 1913 !LoadOmnibox(error) || | |
| 1914 !LoadTextToSpeechVoices(error) || | |
| 1915 !LoadIncognitoMode(error) || | |
| 1916 !LoadContentSecurityPolicy(error)) | |
| 1917 return false; | |
| 1918 | |
| 1919 return true; | |
| 1920 } | |
| 1921 | |
| 1922 bool Extension::LoadDevToolsPage(string16* error) { | |
| 1923 if (!manifest_->HasKey(keys::kDevToolsPage)) | |
| 1924 return true; | |
| 1925 std::string devtools_str; | |
| 1926 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) { | |
| 1927 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage); | |
| 1928 return false; | |
| 1929 } | |
| 1930 devtools_url_ = GetResourceURL(devtools_str); | |
| 1931 return true; | |
| 1932 } | |
| 1933 | |
| 1934 bool Extension::LoadInputComponents( | |
| 1935 const ExtensionAPIPermissionSet& api_permissions, | |
| 1936 string16* error) { | |
| 1937 if (!manifest_->HasKey(keys::kInputComponents)) | |
| 1938 return true; | |
| 1939 ListValue* list_value = NULL; | |
| 1940 if (!manifest_->GetList(keys::kInputComponents, &list_value)) { | |
| 1941 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 1942 return false; | |
| 1943 } | |
| 1944 | |
| 1945 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1946 DictionaryValue* module_value = NULL; | |
| 1947 std::string name_str; | |
| 1948 InputComponentType type; | |
| 1949 std::string id_str; | |
| 1950 std::string description_str; | |
| 1951 std::string language_str; | |
| 1952 std::set<std::string> layouts; | |
| 1953 std::string shortcut_keycode_str; | |
| 1954 bool shortcut_alt = false; | |
| 1955 bool shortcut_ctrl = false; | |
| 1956 bool shortcut_shift = false; | |
| 1957 | |
| 1958 if (!list_value->GetDictionary(i, &module_value)) { | |
| 1959 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 1960 return false; | |
| 1961 } | |
| 1962 | |
| 1963 // Get input_components[i].name. | |
| 1964 if (!module_value->GetString(keys::kName, &name_str)) { | |
| 1965 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1966 errors::kInvalidInputComponentName, base::IntToString(i)); | |
| 1967 return false; | |
| 1968 } | |
| 1969 | |
| 1970 // Get input_components[i].type. | |
| 1971 std::string type_str; | |
| 1972 if (module_value->GetString(keys::kType, &type_str)) { | |
| 1973 if (type_str == "ime") { | |
| 1974 type = INPUT_COMPONENT_TYPE_IME; | |
| 1975 } else if (type_str == "virtual_keyboard") { | |
| 1976 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { | |
| 1977 // Virtual Keyboards require the experimental flag. | |
| 1978 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1979 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 1980 return false; | |
| 1981 } | |
| 1982 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD; | |
| 1983 } else { | |
| 1984 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1985 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 1986 return false; | |
| 1987 } | |
| 1988 } else { | |
| 1989 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1990 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 1991 return false; | |
| 1992 } | |
| 1993 | |
| 1994 // Get input_components[i].id. | |
| 1995 if (!module_value->GetString(keys::kId, &id_str)) { | |
| 1996 id_str = ""; | |
| 1997 } | |
| 1998 | |
| 1999 // Get input_components[i].description. | |
| 2000 if (!module_value->GetString(keys::kDescription, &description_str)) { | |
| 2001 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2002 errors::kInvalidInputComponentDescription, base::IntToString(i)); | |
| 2003 return false; | |
| 2004 } | |
| 2005 // Get input_components[i].language. | |
| 2006 if (!module_value->GetString(keys::kLanguage, &language_str)) { | |
| 2007 language_str = ""; | |
| 2008 } | |
| 2009 | |
| 2010 // Get input_components[i].layouts. | |
| 2011 ListValue* layouts_value = NULL; | |
| 2012 if (!module_value->GetList(keys::kLayouts, &layouts_value)) { | |
| 2013 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts); | |
| 2014 return false; | |
| 2015 } | |
| 2016 | |
| 2017 for (size_t j = 0; j < layouts_value->GetSize(); ++j) { | |
| 2018 std::string layout_name_str; | |
| 2019 if (!layouts_value->GetString(j, &layout_name_str)) { | |
| 2020 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2021 errors::kInvalidInputComponentLayoutName, base::IntToString(i), | |
| 2022 base::IntToString(j)); | |
| 2023 return false; | |
| 2024 } | |
| 2025 layouts.insert(layout_name_str); | |
| 2026 } | |
| 2027 | |
| 2028 if (module_value->HasKey(keys::kShortcutKey)) { | |
| 2029 DictionaryValue* shortcut_value = NULL; | |
| 2030 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) { | |
| 2031 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2032 errors::kInvalidInputComponentShortcutKey, base::IntToString(i)); | |
| 2033 return false; | |
| 2034 } | |
| 2035 | |
| 2036 // Get input_components[i].shortcut_keycode. | |
| 2037 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) { | |
| 2038 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2039 errors::kInvalidInputComponentShortcutKeycode, | |
| 2040 base::IntToString(i)); | |
| 2041 return false; | |
| 2042 } | |
| 2043 | |
| 2044 // Get input_components[i].shortcut_alt. | |
| 2045 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) { | |
| 2046 shortcut_alt = false; | |
| 2047 } | |
| 2048 | |
| 2049 // Get input_components[i].shortcut_ctrl. | |
| 2050 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) { | |
| 2051 shortcut_ctrl = false; | |
| 2052 } | |
| 2053 | |
| 2054 // Get input_components[i].shortcut_shift. | |
| 2055 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) { | |
| 2056 shortcut_shift = false; | |
| 2057 } | |
| 2058 } | |
| 2059 | |
| 2060 input_components_.push_back(InputComponentInfo()); | |
| 2061 input_components_.back().name = name_str; | |
| 2062 input_components_.back().type = type; | |
| 2063 input_components_.back().id = id_str; | |
| 2064 input_components_.back().description = description_str; | |
| 2065 input_components_.back().language = language_str; | |
| 2066 input_components_.back().layouts.insert(layouts.begin(), layouts.end()); | |
| 2067 input_components_.back().shortcut_keycode = shortcut_keycode_str; | |
| 2068 input_components_.back().shortcut_alt = shortcut_alt; | |
| 2069 input_components_.back().shortcut_ctrl = shortcut_ctrl; | |
| 2070 input_components_.back().shortcut_shift = shortcut_shift; | |
| 2071 } | |
| 2072 | |
| 2073 return true; | |
| 2074 } | |
| 2075 | |
| 2076 bool Extension::LoadContentScripts(string16* error) { | |
| 2077 if (!manifest_->HasKey(keys::kContentScripts)) | |
| 2078 return true; | |
| 2079 ListValue* list_value; | |
| 2080 if (!manifest_->GetList(keys::kContentScripts, &list_value)) { | |
| 2081 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList); | |
| 2082 return false; | |
| 2083 } | |
| 2084 | |
| 2085 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2086 DictionaryValue* content_script = NULL; | |
| 2087 if (!list_value->GetDictionary(i, &content_script)) { | |
| 2088 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2089 errors::kInvalidContentScript, base::IntToString(i)); | |
| 2090 return false; | |
| 2091 } | |
| 2092 | |
| 2093 UserScript script; | |
| 2094 if (!LoadUserScriptHelper(content_script, i, error, &script)) | |
| 2095 return false; // Failed to parse script context definition. | |
| 2096 script.set_extension_id(id()); | |
| 2097 if (converted_from_user_script_) { | |
| 2098 script.set_emulate_greasemonkey(true); | |
| 2099 script.set_match_all_frames(true); // Greasemonkey matches all frames. | |
| 2100 } | |
| 2101 content_scripts_.push_back(script); | |
| 2102 } | |
| 2103 return true; | |
| 2104 } | |
| 2105 | |
| 2106 bool Extension::LoadPageAction(string16* error) { | |
| 2107 DictionaryValue* page_action_value = NULL; | |
| 2108 | |
| 2109 if (manifest_->HasKey(keys::kPageActions)) { | |
| 2110 ListValue* list_value = NULL; | |
| 2111 if (!manifest_->GetList(keys::kPageActions, &list_value)) { | |
| 2112 *error = ASCIIToUTF16(errors::kInvalidPageActionsList); | |
| 2113 return false; | |
| 2114 } | |
| 2115 | |
| 2116 size_t list_value_length = list_value->GetSize(); | |
| 2117 | |
| 2118 if (list_value_length == 0u) { | |
| 2119 // A list with zero items is allowed, and is equivalent to not having | |
| 2120 // a page_actions key in the manifest. Don't set |page_action_value|. | |
| 2121 } else if (list_value_length == 1u) { | |
| 2122 if (!list_value->GetDictionary(0, &page_action_value)) { | |
| 2123 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2124 return false; | |
| 2125 } | |
| 2126 } else { // list_value_length > 1u. | |
| 2127 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize); | |
| 2128 return false; | |
| 2129 } | |
| 2130 } else if (manifest_->HasKey(keys::kPageAction)) { | |
| 2131 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { | |
| 2132 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2133 return false; | |
| 2134 } | |
| 2135 } | |
| 2136 | |
| 2137 // If page_action_value is not NULL, then there was a valid page action. | |
| 2138 if (page_action_value) { | |
| 2139 page_action_.reset( | |
| 2140 LoadExtensionActionHelper(page_action_value, error)); | |
| 2141 if (!page_action_.get()) | |
| 2142 return false; // Failed to parse page action definition. | |
| 2143 } | |
| 2144 | |
| 2145 return true; | |
| 2146 } | |
| 2147 | |
| 2148 bool Extension::LoadBrowserAction(string16* error) { | |
| 2149 if (!manifest_->HasKey(keys::kBrowserAction)) | |
| 2150 return true; | |
| 2151 DictionaryValue* browser_action_value = NULL; | |
| 2152 if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) { | |
| 2153 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); | |
| 2154 return false; | |
| 2155 } | |
| 2156 | |
| 2157 browser_action_.reset( | |
| 2158 LoadExtensionActionHelper(browser_action_value, error)); | |
| 2159 if (!browser_action_.get()) | |
| 2160 return false; // Failed to parse browser action definition. | |
| 2161 return true; | |
| 2162 } | |
| 2163 | |
| 2164 bool Extension::LoadFileBrowserHandlers(string16* error) { | |
| 2165 if (!manifest_->HasKey(keys::kFileBrowserHandlers)) | |
| 2166 return true; | |
| 2167 ListValue* file_browser_handlers_value = NULL; | |
| 2168 if (!manifest_->GetList(keys::kFileBrowserHandlers, | |
| 2169 &file_browser_handlers_value)) { | |
| 2170 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2171 return false; | |
| 2172 } | |
| 2173 file_browser_handlers_.reset( | |
| 2174 LoadFileBrowserHandlersHelper(file_browser_handlers_value, error)); | |
| 2175 if (!file_browser_handlers_.get()) | |
| 2176 return false; // Failed to parse file browser actions definition. | |
| 2177 return true; | |
| 2178 } | |
| 2179 | |
| 2180 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlersHelper( | |
| 2181 const ListValue* extension_actions, string16* error) { | |
| 2182 scoped_ptr<FileBrowserHandlerList> result( | |
| 2183 new FileBrowserHandlerList()); | |
| 2184 for (ListValue::const_iterator iter = extension_actions->begin(); | |
| 2185 iter != extension_actions->end(); | |
| 2186 ++iter) { | |
| 2187 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) { | |
| 2188 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2189 return NULL; | |
| 2190 } | |
| 2191 scoped_ptr<FileBrowserHandler> action( | |
| 2192 LoadFileBrowserHandler( | |
| 2193 reinterpret_cast<DictionaryValue*>(*iter), error)); | |
| 2194 if (!action.get()) | |
| 2195 return NULL; // Failed to parse file browser action definition. | |
| 2196 result->push_back(linked_ptr<FileBrowserHandler>(action.release())); | |
| 2197 } | |
| 2198 return result.release(); | |
| 2199 } | |
| 2200 | |
| 2201 FileBrowserHandler* Extension::LoadFileBrowserHandler( | |
| 2202 const DictionaryValue* file_browser_handler, string16* error) { | |
| 2203 scoped_ptr<FileBrowserHandler> result( | |
| 2204 new FileBrowserHandler()); | |
| 2205 result->set_extension_id(id()); | |
| 2206 | |
| 2207 std::string id; | |
| 2208 // Read the file action |id| (mandatory). | |
| 2209 if (!file_browser_handler->HasKey(keys::kPageActionId) || | |
| 2210 !file_browser_handler->GetString(keys::kPageActionId, &id)) { | |
| 2211 *error = ASCIIToUTF16(errors::kInvalidPageActionId); | |
| 2212 return NULL; | |
| 2213 } | |
| 2214 result->set_id(id); | |
| 2215 | |
| 2216 // Read the page action title from |default_title| (mandatory). | |
| 2217 std::string title; | |
| 2218 if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) || | |
| 2219 !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) { | |
| 2220 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); | |
| 2221 return NULL; | |
| 2222 } | |
| 2223 result->set_title(title); | |
| 2224 | |
| 2225 // Initialize file filters (mandatory). | |
| 2226 ListValue* list_value = NULL; | |
| 2227 if (!file_browser_handler->HasKey(keys::kFileFilters) || | |
| 2228 !file_browser_handler->GetList(keys::kFileFilters, &list_value) || | |
| 2229 list_value->empty()) { | |
| 2230 *error = ASCIIToUTF16(errors::kInvalidFileFiltersList); | |
| 2231 return NULL; | |
| 2232 } | |
| 2233 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2234 std::string filter; | |
| 2235 if (!list_value->GetString(i, &filter)) { | |
| 2236 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2237 errors::kInvalidFileFilterValue, base::IntToString(i)); | |
| 2238 return NULL; | |
| 2239 } | |
| 2240 StringToLowerASCII(&filter); | |
| 2241 URLPattern pattern(URLPattern::SCHEME_FILESYSTEM); | |
| 2242 if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) { | |
| 2243 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2244 errors::kInvalidURLPatternError, filter); | |
| 2245 return NULL; | |
| 2246 } | |
| 2247 std::string path = pattern.path(); | |
| 2248 bool allowed = path == "*" || path == "*.*" || | |
| 2249 (path.compare(0, 2, "*.") == 0 && | |
| 2250 path.find_first_of('*', 2) == std::string::npos); | |
| 2251 if (!allowed) { | |
| 2252 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2253 errors::kInvalidURLPatternError, filter); | |
| 2254 return NULL; | |
| 2255 } | |
| 2256 result->AddPattern(pattern); | |
| 2257 } | |
| 2258 | |
| 2259 std::string default_icon; | |
| 2260 // Read the file browser action |default_icon| (optional). | |
| 2261 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { | |
| 2262 if (!file_browser_handler->GetString( | |
| 2263 keys::kPageActionDefaultIcon, &default_icon) || | |
| 2264 default_icon.empty()) { | |
| 2265 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | |
| 2266 return NULL; | |
| 2267 } | |
| 2268 result->set_icon_path(default_icon); | |
| 2269 } | |
| 2270 | |
| 2271 return result.release(); | |
| 2272 } | |
| 2273 | |
| 2274 bool Extension::LoadChromeURLOverrides(string16* error) { | |
| 2275 if (!manifest_->HasKey(keys::kChromeURLOverrides)) | |
| 2276 return true; | |
| 2277 DictionaryValue* overrides = NULL; | |
| 2278 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) { | |
| 2279 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2280 return false; | |
| 2281 } | |
| 2282 | |
| 2283 // Validate that the overrides are all strings | |
| 2284 for (DictionaryValue::key_iterator iter = overrides->begin_keys(); | |
| 2285 iter != overrides->end_keys(); ++iter) { | |
| 2286 std::string page = *iter; | |
| 2287 std::string val; | |
| 2288 // Restrict override pages to a list of supported URLs. | |
| 2289 if ((page != chrome::kChromeUINewTabHost && | |
| 2290 #if defined(USE_VIRTUAL_KEYBOARD) | |
| 2291 page != chrome::kChromeUIKeyboardHost && | |
| 2292 #endif | |
| 2293 #if defined(OS_CHROMEOS) | |
| 2294 page != chrome::kChromeUIActivationMessageHost && | |
| 2295 #endif | |
| 2296 page != chrome::kChromeUIBookmarksHost && | |
| 2297 page != chrome::kChromeUIHistoryHost | |
| 2298 #if defined(FILE_MANAGER_EXTENSION) | |
| 2299 && | |
| 2300 !(location() == COMPONENT && | |
| 2301 page == chrome::kChromeUIFileManagerHost) | |
| 2302 #endif | |
| 2303 ) || | |
| 2304 !overrides->GetStringWithoutPathExpansion(*iter, &val)) { | |
| 2305 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2306 return false; | |
| 2307 } | |
| 2308 // Replace the entry with a fully qualified chrome-extension:// URL. | |
| 2309 chrome_url_overrides_[page] = GetResourceURL(val); | |
| 2310 } | |
| 2311 | |
| 2312 // An extension may override at most one page. | |
| 2313 if (overrides->size() > 1) { | |
| 2314 *error = ASCIIToUTF16(errors::kMultipleOverrides); | |
| 2315 return false; | |
| 2316 } | |
| 2317 | |
| 2318 return true; | |
| 2319 } | |
| 2320 | |
| 2321 bool Extension::LoadOmnibox(string16* error) { | |
| 2322 if (!manifest_->HasKey(keys::kOmnibox)) | |
| 2323 return true; | |
| 2324 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || | |
| 2325 omnibox_keyword_.empty()) { | |
| 2326 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword); | |
| 2327 return false; | |
| 2328 } | |
| 2329 return true; | |
| 2330 } | |
| 2331 | |
| 2332 bool Extension::LoadTextToSpeechVoices(string16* error) { | |
| 2333 if (!manifest_->HasKey(keys::kTtsEngine)) | |
| 2334 return true; | |
| 2335 DictionaryValue* tts_dict = NULL; | |
| 2336 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) { | |
| 2337 *error = ASCIIToUTF16(errors::kInvalidTts); | |
| 2338 return false; | |
| 2339 } | |
| 2340 | |
| 2341 if (tts_dict->HasKey(keys::kTtsVoices)) { | |
| 2342 ListValue* tts_voices = NULL; | |
| 2343 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) { | |
| 2344 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2345 return false; | |
| 2346 } | |
| 2347 | |
| 2348 for (size_t i = 0; i < tts_voices->GetSize(); i++) { | |
| 2349 DictionaryValue* one_tts_voice = NULL; | |
| 2350 if (!tts_voices->GetDictionary(i, &one_tts_voice)) { | |
| 2351 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2352 return false; | |
| 2353 } | |
| 2354 | |
| 2355 TtsVoice voice_data; | |
| 2356 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) { | |
| 2357 if (!one_tts_voice->GetString( | |
| 2358 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) { | |
| 2359 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName); | |
| 2360 return false; | |
| 2361 } | |
| 2362 } | |
| 2363 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) { | |
| 2364 if (!one_tts_voice->GetString( | |
| 2365 keys::kTtsVoicesLang, &voice_data.lang) || | |
| 2366 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) { | |
| 2367 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang); | |
| 2368 return false; | |
| 2369 } | |
| 2370 } | |
| 2371 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) { | |
| 2372 if (!one_tts_voice->GetString( | |
| 2373 keys::kTtsVoicesGender, &voice_data.gender) || | |
| 2374 (voice_data.gender != keys::kTtsGenderMale && | |
| 2375 voice_data.gender != keys::kTtsGenderFemale)) { | |
| 2376 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender); | |
| 2377 return false; | |
| 2378 } | |
| 2379 } | |
| 2380 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) { | |
| 2381 ListValue* event_types_list; | |
| 2382 if (!one_tts_voice->GetList( | |
| 2383 keys::kTtsVoicesEventTypes, &event_types_list)) { | |
| 2384 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2385 return false; | |
| 2386 } | |
| 2387 for (size_t i = 0; i < event_types_list->GetSize(); i++) { | |
| 2388 std::string event_type; | |
| 2389 if (!event_types_list->GetString(i, &event_type)) { | |
| 2390 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2391 return false; | |
| 2392 } | |
| 2393 if (event_type != keys::kTtsVoicesEventTypeEnd && | |
| 2394 event_type != keys::kTtsVoicesEventTypeError && | |
| 2395 event_type != keys::kTtsVoicesEventTypeMarker && | |
| 2396 event_type != keys::kTtsVoicesEventTypeSentence && | |
| 2397 event_type != keys::kTtsVoicesEventTypeStart && | |
| 2398 event_type != keys::kTtsVoicesEventTypeWord) { | |
| 2399 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2400 return false; | |
| 2401 } | |
| 2402 if (voice_data.event_types.find(event_type) != | |
| 2403 voice_data.event_types.end()) { | |
| 2404 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2405 return false; | |
| 2406 } | |
| 2407 voice_data.event_types.insert(event_type); | |
| 2408 } | |
| 2409 } | |
| 2410 | |
| 2411 tts_voices_.push_back(voice_data); | |
| 2412 } | |
| 2413 } | |
| 2414 return true; | |
| 2415 } | |
| 2416 | |
| 2417 bool Extension::LoadIncognitoMode(string16* error) { | |
| 2418 // Apps default to split mode, extensions default to spanning. | |
| 2419 incognito_split_mode_ = is_app(); | |
| 2420 if (!manifest_->HasKey(keys::kIncognito)) | |
| 2421 return true; | |
| 2422 std::string value; | |
| 2423 if (!manifest_->GetString(keys::kIncognito, &value)) { | |
| 2424 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2425 return false; | |
| 2426 } | |
| 2427 if (value == values::kIncognitoSpanning) { | |
| 2428 incognito_split_mode_ = false; | |
| 2429 } else if (value == values::kIncognitoSplit) { | |
| 2430 incognito_split_mode_ = true; | |
| 2431 } else { | |
| 2432 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2433 return false; | |
| 2434 } | |
| 2435 return true; | |
| 2436 } | |
| 2437 | |
| 2438 bool Extension::LoadContentSecurityPolicy(string16* error) { | |
| 2439 if (manifest_->HasKey(keys::kContentSecurityPolicy)) { | |
| 2440 std::string content_security_policy; | |
| 2441 if (!manifest_->GetString(keys::kContentSecurityPolicy, | |
| 2442 &content_security_policy)) { | |
| 2443 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2444 return false; | |
| 2445 } | |
| 2446 if (!ContentSecurityPolicyIsLegal(content_security_policy)) { | |
| 2447 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2448 return false; | |
| 2449 } | |
| 2450 if (manifest_version_ >= 2 && | |
| 2451 !ContentSecurityPolicyIsSecure(content_security_policy)) { | |
| 2452 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2453 return false; | |
| 2454 } | |
| 2455 | |
| 2456 content_security_policy_ = content_security_policy; | |
| 2457 } else if (manifest_version_ >= 2) { | |
| 2458 // Manifest version 2 introduced a default Content-Security-Policy. | |
| 2459 // TODO(abarth): Should we continue to let extensions override the | |
| 2460 // default Content-Security-Policy? | |
| 2461 content_security_policy_ = kDefaultContentSecurityPolicy; | |
| 2462 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_)); | |
| 2463 } | |
| 2464 return true; | |
| 2465 } | |
| 2466 | |
| 2467 bool Extension::LoadAppIsolation(string16* error) { | |
| 2468 Value* temp = NULL; | |
| 2469 if (!manifest_->Get(keys::kIsolation, &temp)) | |
| 2470 return true; | |
| 2471 | |
| 2472 if (temp->GetType() != Value::TYPE_LIST) { | |
| 2473 *error = ASCIIToUTF16(errors::kInvalidIsolation); | |
| 2474 return false; | |
| 2475 } | |
| 2476 | |
| 2477 ListValue* isolation_list = static_cast<ListValue*>(temp); | |
| 2478 for (size_t i = 0; i < isolation_list->GetSize(); ++i) { | |
| 2479 std::string isolation_string; | |
| 2480 if (!isolation_list->GetString(i, &isolation_string)) { | |
| 2481 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2482 errors::kInvalidIsolationValue, | |
| 2483 base::UintToString(i)); | |
| 2484 return false; | |
| 2485 } | |
| 2486 | |
| 2487 // Check for isolated storage. | |
| 2488 if (isolation_string == values::kIsolatedStorage) { | |
| 2489 is_storage_isolated_ = true; | |
| 2490 } else { | |
| 2491 DLOG(WARNING) << "Did not recognize isolation type: " | |
| 2492 << isolation_string; | |
| 2493 } | |
| 2494 } | |
| 2495 return true; | |
| 2496 } | |
| 2497 | |
| 2498 bool Extension::LoadThemeFeatures(string16* error) { | |
| 2499 if (!manifest_->HasKey(keys::kTheme)) | |
| 2500 return true; | |
| 2501 DictionaryValue* theme_value = NULL; | |
| 2502 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { | |
| 2503 *error = ASCIIToUTF16(errors::kInvalidTheme); | |
| 2504 return false; | |
| 2505 } | |
| 2506 if (!LoadThemeImages(theme_value, error)) | |
| 2507 return false; | |
| 2508 if (!LoadThemeColors(theme_value, error)) | |
| 2509 return false; | |
| 2510 if (!LoadThemeTints(theme_value, error)) | |
| 2511 return false; | |
| 2512 if (!LoadThemeDisplayProperties(theme_value, error)) | |
| 2513 return false; | |
| 2514 | |
| 2515 return true; | |
| 2516 } | |
| 2517 | |
| 2518 bool Extension::LoadThemeImages(const DictionaryValue* theme_value, | |
| 2519 string16* error) { | |
| 2520 DictionaryValue* images_value = NULL; | |
| 2521 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { | |
| 2522 // Validate that the images are all strings | |
| 2523 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); | |
| 2524 iter != images_value->end_keys(); ++iter) { | |
| 2525 std::string val; | |
| 2526 if (!images_value->GetString(*iter, &val)) { | |
| 2527 *error = ASCIIToUTF16(errors::kInvalidThemeImages); | |
| 2528 return false; | |
| 2529 } | |
| 2530 } | |
| 2531 theme_images_.reset(images_value->DeepCopy()); | |
| 2532 } | |
| 2533 return true; | |
| 2534 } | |
| 2535 | |
| 2536 bool Extension::LoadThemeColors(const DictionaryValue* theme_value, | |
| 2537 string16* error) { | |
| 2538 DictionaryValue* colors_value = NULL; | |
| 2539 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { | |
| 2540 // Validate that the colors are RGB or RGBA lists | |
| 2541 for (DictionaryValue::key_iterator iter = colors_value->begin_keys(); | |
| 2542 iter != colors_value->end_keys(); ++iter) { | |
| 2543 ListValue* color_list = NULL; | |
| 2544 double alpha = 0.0; | |
| 2545 int color = 0; | |
| 2546 // The color must be a list | |
| 2547 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) || | |
| 2548 // And either 3 items (RGB) or 4 (RGBA) | |
| 2549 ((color_list->GetSize() != 3) && | |
| 2550 ((color_list->GetSize() != 4) || | |
| 2551 // For RGBA, the fourth item must be a real or int alpha value. | |
| 2552 // Note that GetDouble() can get an integer value. | |
| 2553 !color_list->GetDouble(3, &alpha))) || | |
| 2554 // For both RGB and RGBA, the first three items must be ints (R,G,B) | |
| 2555 !color_list->GetInteger(0, &color) || | |
| 2556 !color_list->GetInteger(1, &color) || | |
| 2557 !color_list->GetInteger(2, &color)) { | |
| 2558 *error = ASCIIToUTF16(errors::kInvalidThemeColors); | |
| 2559 return false; | |
| 2560 } | |
| 2561 } | |
| 2562 theme_colors_.reset(colors_value->DeepCopy()); | |
| 2563 } | |
| 2564 return true; | |
| 2565 } | |
| 2566 | |
| 2567 bool Extension::LoadThemeTints(const DictionaryValue* theme_value, | |
| 2568 string16* error) { | |
| 2569 DictionaryValue* tints_value = NULL; | |
| 2570 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) { | |
| 2571 // Validate that the tints are all reals. | |
| 2572 for (DictionaryValue::key_iterator iter = tints_value->begin_keys(); | |
| 2573 iter != tints_value->end_keys(); ++iter) { | |
| 2574 ListValue* tint_list = NULL; | |
| 2575 double v = 0.0; | |
| 2576 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) || | |
| 2577 tint_list->GetSize() != 3 || | |
| 2578 !tint_list->GetDouble(0, &v) || | |
| 2579 !tint_list->GetDouble(1, &v) || | |
| 2580 !tint_list->GetDouble(2, &v)) { | |
| 2581 *error = ASCIIToUTF16(errors::kInvalidThemeTints); | |
| 2582 return false; | |
| 2583 } | |
| 2584 } | |
| 2585 theme_tints_.reset(tints_value->DeepCopy()); | |
| 2586 } | |
| 2587 return true; | |
| 2588 } | |
| 2589 | |
| 2590 bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value, | |
| 2591 string16* error) { | |
| 2592 DictionaryValue* display_properties_value = NULL; | |
| 2593 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, | |
| 2594 &display_properties_value)) { | |
| 2595 theme_display_properties_.reset( | |
| 2596 display_properties_value->DeepCopy()); | |
| 2597 } | |
| 2598 return true; | |
| 2599 } | |
| 2600 | |
| 1539 // static | 2601 // static |
| 1540 bool Extension::IsTrustedId(const std::string& id) { | 2602 bool Extension::IsTrustedId(const std::string& id) { |
| 1541 // See http://b/4946060 for more details. | 2603 // See http://b/4946060 for more details. |
| 1542 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); | 2604 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); |
| 1543 } | 2605 } |
| 1544 | 2606 |
| 1545 Extension::Extension(const FilePath& path, | 2607 Extension::Extension(const FilePath& path, |
| 1546 scoped_ptr<extensions::Manifest> manifest) | 2608 scoped_ptr<extensions::Manifest> manifest) |
| 1547 : manifest_version_(0), | 2609 : manifest_version_(0), |
| 1548 incognito_split_mode_(false), | 2610 incognito_split_mode_(false), |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1712 const SkBitmap& Extension::GetDefaultIcon(bool is_app) { | 2774 const SkBitmap& Extension::GetDefaultIcon(bool is_app) { |
| 1713 if (is_app) { | 2775 if (is_app) { |
| 1714 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | 2776 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 1715 IDR_APP_DEFAULT_ICON); | 2777 IDR_APP_DEFAULT_ICON); |
| 1716 } else { | 2778 } else { |
| 1717 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | 2779 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 1718 IDR_EXTENSION_DEFAULT_ICON); | 2780 IDR_EXTENSION_DEFAULT_ICON); |
| 1719 } | 2781 } |
| 1720 } | 2782 } |
| 1721 | 2783 |
| 2784 // static | |
| 1722 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { | 2785 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { |
| 1723 return GURL(std::string(chrome::kExtensionScheme) + | 2786 return GURL(std::string(chrome::kExtensionScheme) + |
| 1724 chrome::kStandardSchemeSeparator + extension_id + "/"); | 2787 chrome::kStandardSchemeSeparator + extension_id + "/"); |
| 1725 } | 2788 } |
| 1726 | 2789 |
| 1727 bool Extension::LoadManifestVersion(string16* error) { | |
| 1728 // Get the original value out of the dictionary so that we can validate it | |
| 1729 // more strictly. | |
| 1730 if (manifest_->value()->HasKey(keys::kManifestVersion)) { | |
| 1731 int manifest_version = 1; | |
| 1732 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) || | |
| 1733 manifest_version < 1) { | |
| 1734 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1735 return false; | |
| 1736 } | |
| 1737 } | |
| 1738 | |
| 1739 manifest_version_ = manifest_->GetManifestVersion(); | |
| 1740 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION && | |
| 1741 manifest_version_ < kModernManifestVersion && | |
| 1742 !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1743 switches::kAllowLegacyExtensionManifests)) { | |
| 1744 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1745 return false; | |
| 1746 } | |
| 1747 | |
| 1748 return true; | |
| 1749 } | |
| 1750 | |
| 1751 // static | |
| 1752 bool Extension::InitExtensionID(extensions::Manifest* manifest, | |
| 1753 const FilePath& path, | |
| 1754 const std::string& explicit_id, | |
| 1755 int creation_flags, | |
| 1756 string16* error) { | |
| 1757 if (!explicit_id.empty()) { | |
| 1758 manifest->set_extension_id(explicit_id); | |
| 1759 return true; | |
| 1760 } | |
| 1761 | |
| 1762 if (manifest->HasKey(keys::kPublicKey)) { | |
| 1763 std::string public_key; | |
| 1764 std::string public_key_bytes; | |
| 1765 std::string extension_id; | |
| 1766 if (!manifest->GetString(keys::kPublicKey, &public_key) || | |
| 1767 !ParsePEMKeyBytes(public_key, &public_key_bytes) || | |
| 1768 !GenerateId(public_key_bytes, &extension_id)) { | |
| 1769 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 1770 return false; | |
| 1771 } | |
| 1772 manifest->set_extension_id(extension_id); | |
| 1773 return true; | |
| 1774 } | |
| 1775 | |
| 1776 if (creation_flags & REQUIRE_KEY) { | |
| 1777 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 1778 return false; | |
| 1779 } else { | |
| 1780 // If there is a path, we generate the ID from it. This is useful for | |
| 1781 // development mode, because it keeps the ID stable across restarts and | |
| 1782 // reloading the extension. | |
| 1783 std::string extension_id = GenerateIdForPath(path); | |
| 1784 if (extension_id.empty()) { | |
| 1785 NOTREACHED() << "Could not create ID from path."; | |
| 1786 return false; | |
| 1787 } | |
| 1788 manifest->set_extension_id(extension_id); | |
| 1789 return true; | |
| 1790 } | |
| 1791 } | |
| 1792 | |
| 1793 bool Extension::InitFromValue(int flags, string16* error) { | 2790 bool Extension::InitFromValue(int flags, string16* error) { |
| 1794 DCHECK(error); | 2791 DCHECK(error); |
| 1795 | 2792 |
| 1796 base::AutoLock auto_lock(runtime_data_lock_); | 2793 base::AutoLock auto_lock(runtime_data_lock_); |
| 1797 | 2794 |
| 1798 // Initialize permissions with an empty, default permission set. | 2795 // Initialize permissions with an empty, default permission set. |
| 1799 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); | 2796 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); |
| 1800 optional_permission_set_ = new ExtensionPermissionSet(); | 2797 optional_permission_set_ = new ExtensionPermissionSet(); |
| 1801 required_permission_set_ = new ExtensionPermissionSet(); | 2798 required_permission_set_ = new ExtensionPermissionSet(); |
| 1802 | 2799 |
| 1803 creation_flags_ = flags; | 2800 creation_flags_ = flags; |
| 1804 | 2801 |
| 1805 if (!LoadManifestVersion(error)) | 2802 // Validate minimum Chrome version. We don't need to store this, since the |
| 2803 // extension is not valid if it is incorrect | |
| 2804 if (!CheckMinimumChromeVersion(error)) | |
| 2805 return false; | |
| 2806 | |
| 2807 if (!LoadRequiredFeatures(error)) | |
| 1806 return false; | 2808 return false; |
| 1807 | 2809 |
| 1808 // We don't ned to validate because InitExtensionID already did that. | 2810 // We don't ned to validate because InitExtensionID already did that. |
| 1809 manifest_->GetString(keys::kPublicKey, &public_key_); | 2811 manifest_->GetString(keys::kPublicKey, &public_key_); |
| 1810 | 2812 |
| 1811 // Initialize the URL. | 2813 // Initialize permissions with an empty, default permission set. |
| 2814 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); | |
| 2815 optional_permission_set_ = new ExtensionPermissionSet(); | |
| 2816 required_permission_set_ = new ExtensionPermissionSet(); | |
| 2817 | |
| 1812 extension_url_ = Extension::GetBaseURLFromExtensionId(id()); | 2818 extension_url_ = Extension::GetBaseURLFromExtensionId(id()); |
| 1813 | 2819 |
| 1814 // Initialize version. | |
| 1815 std::string version_str; | |
| 1816 if (!manifest_->GetString(keys::kVersion, &version_str)) { | |
| 1817 *error = ASCIIToUTF16(errors::kInvalidVersion); | |
| 1818 return false; | |
| 1819 } | |
| 1820 version_.reset(Version::GetVersionFromString(version_str)); | |
| 1821 if (!version_.get() || | |
| 1822 version_->components().size() > 4) { | |
| 1823 *error = ASCIIToUTF16(errors::kInvalidVersion); | |
| 1824 return false; | |
| 1825 } | |
| 1826 | |
| 1827 // Initialize name. | |
| 1828 string16 localized_name; | |
| 1829 if (!manifest_->GetString(keys::kName, &localized_name)) { | |
| 1830 *error = ASCIIToUTF16(errors::kInvalidName); | |
| 1831 return false; | |
| 1832 } | |
| 1833 base::i18n::AdjustStringForLocaleDirection(&localized_name); | |
| 1834 name_ = UTF16ToUTF8(localized_name); | |
| 1835 | |
| 1836 // Load App settings. LoadExtent at least has to be done before | 2820 // Load App settings. LoadExtent at least has to be done before |
| 1837 // ParsePermissions(), because the valid permissions depend on what type of | 2821 // ParsePermissions(), because the valid permissions depend on what type of |
| 1838 // package this is. | 2822 // package this is. |
| 1839 if (is_app() && | 2823 if (is_app() && !LoadAppFeatures(error)) |
| 1840 (!LoadExtent(keys::kWebURLs, &extent_,errors::kInvalidWebURLs, | 2824 return false; |
| 1841 errors::kInvalidWebURL, error) || | 2825 |
| 1842 !LoadLaunchURL(error) || | |
| 1843 !LoadLaunchContainer(error))) { | |
| 1844 return false; | |
| 1845 } | |
| 1846 | |
| 1847 if (is_platform_app()) { | |
| 1848 if (launch_container() != extension_misc::LAUNCH_SHELL) { | |
| 1849 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform); | |
| 1850 return false; | |
| 1851 } | |
| 1852 } else if (launch_container() == extension_misc::LAUNCH_SHELL) { | |
| 1853 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform); | |
| 1854 return false; | |
| 1855 } | |
| 1856 | |
| 1857 // Initialize the permissions (optional). | |
| 1858 ExtensionAPIPermissionSet api_permissions; | 2826 ExtensionAPIPermissionSet api_permissions; |
| 1859 URLPatternSet host_permissions; | 2827 URLPatternSet host_permissions; |
| 1860 if (!ParsePermissions(keys::kPermissions, | 2828 if (!ParsePermissions(keys::kPermissions, |
| 1861 flags, | |
| 1862 error, | 2829 error, |
| 1863 &api_permissions, | 2830 &api_permissions, |
| 1864 &host_permissions)) { | 2831 &host_permissions)) { |
| 1865 return false; | 2832 return false; |
| 1866 } | 2833 } |
| 1867 | 2834 |
| 1868 // Initialize the optional permissions (optional). | |
| 1869 ExtensionAPIPermissionSet optional_api_permissions; | 2835 ExtensionAPIPermissionSet optional_api_permissions; |
| 1870 URLPatternSet optional_host_permissions; | 2836 URLPatternSet optional_host_permissions; |
| 1871 if (!ParsePermissions(keys::kOptionalPermissions, | 2837 if (!ParsePermissions(keys::kOptionalPermissions, |
| 1872 flags, | |
| 1873 error, | 2838 error, |
| 1874 &optional_api_permissions, | 2839 &optional_api_permissions, |
| 1875 &optional_host_permissions)) { | 2840 &optional_host_permissions)) { |
| 1876 return false; | 2841 return false; |
| 1877 } | 2842 } |
| 1878 | 2843 |
| 1879 // Initialize description (if present). | |
| 1880 if (manifest_->HasKey(keys::kDescription)) { | |
| 1881 if (!manifest_->GetString(keys::kDescription, &description_)) { | |
| 1882 *error = ASCIIToUTF16(errors::kInvalidDescription); | |
| 1883 return false; | |
| 1884 } | |
| 1885 } | |
| 1886 | |
| 1887 // Initialize homepage url (if present). | |
| 1888 if (manifest_->HasKey(keys::kHomepageURL)) { | |
| 1889 std::string tmp; | |
| 1890 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) { | |
| 1891 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1892 errors::kInvalidHomepageURL, ""); | |
| 1893 return false; | |
| 1894 } | |
| 1895 homepage_url_ = GURL(tmp); | |
| 1896 if (!homepage_url_.is_valid() || | |
| 1897 (!homepage_url_.SchemeIs("http") && | |
| 1898 !homepage_url_.SchemeIs("https"))) { | |
| 1899 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1900 errors::kInvalidHomepageURL, tmp); | |
| 1901 return false; | |
| 1902 } | |
| 1903 } | |
| 1904 | |
| 1905 // Initialize update url (if present). | |
| 1906 if (manifest_->HasKey(keys::kUpdateURL)) { | |
| 1907 std::string tmp; | |
| 1908 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) { | |
| 1909 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1910 errors::kInvalidUpdateURL, ""); | |
| 1911 return false; | |
| 1912 } | |
| 1913 update_url_ = GURL(tmp); | |
| 1914 if (!update_url_.is_valid() || | |
| 1915 update_url_.has_ref()) { | |
| 1916 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1917 errors::kInvalidUpdateURL, tmp); | |
| 1918 return false; | |
| 1919 } | |
| 1920 } | |
| 1921 | |
| 1922 // Validate minimum Chrome version (if present). We don't need to store this, | |
| 1923 // since the extension is not valid if it is incorrect. | |
| 1924 if (manifest_->HasKey(keys::kMinimumChromeVersion)) { | |
| 1925 std::string minimum_version_string; | |
| 1926 if (!manifest_->GetString(keys::kMinimumChromeVersion, | |
| 1927 &minimum_version_string)) { | |
| 1928 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); | |
| 1929 return false; | |
| 1930 } | |
| 1931 | |
| 1932 scoped_ptr<Version> minimum_version( | |
| 1933 Version::GetVersionFromString(minimum_version_string)); | |
| 1934 if (!minimum_version.get()) { | |
| 1935 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); | |
| 1936 return false; | |
| 1937 } | |
| 1938 | |
| 1939 chrome::VersionInfo current_version_info; | |
| 1940 if (!current_version_info.is_valid()) { | |
| 1941 NOTREACHED(); | |
| 1942 return false; | |
| 1943 } | |
| 1944 | |
| 1945 scoped_ptr<Version> current_version( | |
| 1946 Version::GetVersionFromString(current_version_info.Version())); | |
| 1947 if (!current_version.get()) { | |
| 1948 DCHECK(false); | |
| 1949 return false; | |
| 1950 } | |
| 1951 | |
| 1952 if (current_version->CompareTo(*minimum_version) < 0) { | |
| 1953 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1954 errors::kChromeVersionTooLow, | |
| 1955 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME), | |
| 1956 minimum_version_string); | |
| 1957 return false; | |
| 1958 } | |
| 1959 } | |
| 1960 | |
| 1961 // Initialize converted_from_user_script (if present) | |
| 1962 if (manifest_->HasKey(keys::kConvertedFromUserScript)) | |
| 1963 manifest_->GetBoolean(keys::kConvertedFromUserScript, | |
| 1964 &converted_from_user_script_); | |
| 1965 | |
| 1966 // Initialize commands (if present). | |
| 1967 if (manifest_->HasKey(keys::kCommands)) { | |
| 1968 DictionaryValue* commands = NULL; | |
| 1969 if (!manifest_->GetDictionary(keys::kCommands, &commands)) { | |
| 1970 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); | |
| 1971 return false; | |
| 1972 } | |
| 1973 | |
| 1974 int command_index = 0; | |
| 1975 for (DictionaryValue::key_iterator iter = commands->begin_keys(); | |
| 1976 iter != commands->end_keys(); ++iter) { | |
| 1977 ++command_index; | |
| 1978 | |
| 1979 DictionaryValue* command = NULL; | |
| 1980 if (!commands->GetDictionary(*iter, &command)) { | |
| 1981 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1982 errors::kInvalidKeyBindingDictionary, | |
| 1983 base::IntToString(command_index)); | |
| 1984 return false; | |
| 1985 } | |
| 1986 | |
| 1987 ExtensionKeybinding binding; | |
| 1988 if (!binding.Parse(command, *iter, command_index, error)) | |
| 1989 return false; // |error| already set. | |
| 1990 | |
| 1991 commands_.push_back(binding); | |
| 1992 } | |
| 1993 } | |
| 1994 | |
| 1995 // Initialize icons (if present). | |
| 1996 if (manifest_->HasKey(keys::kIcons)) { | |
| 1997 DictionaryValue* icons_value = NULL; | |
| 1998 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) { | |
| 1999 *error = ASCIIToUTF16(errors::kInvalidIcons); | |
| 2000 return false; | |
| 2001 } | |
| 2002 | |
| 2003 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) { | |
| 2004 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]); | |
| 2005 if (icons_value->HasKey(key)) { | |
| 2006 std::string icon_path; | |
| 2007 if (!icons_value->GetString(key, &icon_path)) { | |
| 2008 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2009 errors::kInvalidIconPath, key); | |
| 2010 return false; | |
| 2011 } | |
| 2012 | |
| 2013 if (!icon_path.empty() && icon_path[0] == '/') | |
| 2014 icon_path = icon_path.substr(1); | |
| 2015 | |
| 2016 if (icon_path.empty()) { | |
| 2017 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2018 errors::kInvalidIconPath, key); | |
| 2019 return false; | |
| 2020 } | |
| 2021 | |
| 2022 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path); | |
| 2023 } | |
| 2024 } | |
| 2025 } | |
| 2026 | |
| 2027 // Initialize themes (if present). | |
| 2028 if (manifest_->HasKey(keys::kTheme)) { | |
| 2029 DictionaryValue* theme_value = NULL; | |
| 2030 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { | |
| 2031 *error = ASCIIToUTF16(errors::kInvalidTheme); | |
| 2032 return false; | |
| 2033 } | |
| 2034 | |
| 2035 DictionaryValue* images_value = NULL; | |
| 2036 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { | |
| 2037 // Validate that the images are all strings | |
| 2038 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); | |
| 2039 iter != images_value->end_keys(); ++iter) { | |
| 2040 std::string val; | |
| 2041 if (!images_value->GetString(*iter, &val)) { | |
| 2042 *error = ASCIIToUTF16(errors::kInvalidThemeImages); | |
| 2043 return false; | |
| 2044 } | |
| 2045 } | |
| 2046 theme_images_.reset(images_value->DeepCopy()); | |
| 2047 } | |
| 2048 | |
| 2049 DictionaryValue* colors_value = NULL; | |
| 2050 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { | |
| 2051 // Validate that the colors are RGB or RGBA lists | |
| 2052 for (DictionaryValue::key_iterator iter = colors_value->begin_keys(); | |
| 2053 iter != colors_value->end_keys(); ++iter) { | |
| 2054 ListValue* color_list = NULL; | |
| 2055 double alpha = 0.0; | |
| 2056 int color = 0; | |
| 2057 // The color must be a list | |
| 2058 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) || | |
| 2059 // And either 3 items (RGB) or 4 (RGBA) | |
| 2060 ((color_list->GetSize() != 3) && | |
| 2061 ((color_list->GetSize() != 4) || | |
| 2062 // For RGBA, the fourth item must be a real or int alpha value. | |
| 2063 // Note that GetDouble() can get an integer value. | |
| 2064 !color_list->GetDouble(3, &alpha))) || | |
| 2065 // For both RGB and RGBA, the first three items must be ints (R,G,B) | |
| 2066 !color_list->GetInteger(0, &color) || | |
| 2067 !color_list->GetInteger(1, &color) || | |
| 2068 !color_list->GetInteger(2, &color)) { | |
| 2069 *error = ASCIIToUTF16(errors::kInvalidThemeColors); | |
| 2070 return false; | |
| 2071 } | |
| 2072 } | |
| 2073 theme_colors_.reset(colors_value->DeepCopy()); | |
| 2074 } | |
| 2075 | |
| 2076 DictionaryValue* tints_value = NULL; | |
| 2077 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) { | |
| 2078 // Validate that the tints are all reals. | |
| 2079 for (DictionaryValue::key_iterator iter = tints_value->begin_keys(); | |
| 2080 iter != tints_value->end_keys(); ++iter) { | |
| 2081 ListValue* tint_list = NULL; | |
| 2082 double v = 0.0; | |
| 2083 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) || | |
| 2084 tint_list->GetSize() != 3 || | |
| 2085 !tint_list->GetDouble(0, &v) || | |
| 2086 !tint_list->GetDouble(1, &v) || | |
| 2087 !tint_list->GetDouble(2, &v)) { | |
| 2088 *error = ASCIIToUTF16(errors::kInvalidThemeTints); | |
| 2089 return false; | |
| 2090 } | |
| 2091 } | |
| 2092 theme_tints_.reset(tints_value->DeepCopy()); | |
| 2093 } | |
| 2094 | |
| 2095 DictionaryValue* display_properties_value = NULL; | |
| 2096 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, | |
| 2097 &display_properties_value)) { | |
| 2098 theme_display_properties_.reset( | |
| 2099 display_properties_value->DeepCopy()); | |
| 2100 } | |
| 2101 | |
| 2102 return true; | |
| 2103 } | |
| 2104 | |
| 2105 // Initialize plugins (optional). | |
| 2106 if (manifest_->HasKey(keys::kPlugins)) { | |
| 2107 ListValue* list_value = NULL; | |
| 2108 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | |
| 2109 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 2110 return false; | |
| 2111 } | |
| 2112 | |
| 2113 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2114 DictionaryValue* plugin_value = NULL; | |
| 2115 std::string path_str; | |
| 2116 bool is_public = false; | |
| 2117 | |
| 2118 if (!list_value->GetDictionary(i, &plugin_value)) { | |
| 2119 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 2120 return false; | |
| 2121 } | |
| 2122 | |
| 2123 // Get plugins[i].path. | |
| 2124 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) { | |
| 2125 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2126 errors::kInvalidPluginsPath, base::IntToString(i)); | |
| 2127 return false; | |
| 2128 } | |
| 2129 | |
| 2130 // Get plugins[i].content (optional). | |
| 2131 if (plugin_value->HasKey(keys::kPluginsPublic)) { | |
| 2132 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) { | |
| 2133 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2134 errors::kInvalidPluginsPublic, base::IntToString(i)); | |
| 2135 return false; | |
| 2136 } | |
| 2137 } | |
| 2138 | |
| 2139 // We don't allow extension plugins to run on Chrome OS. We still | |
| 2140 // parse the manifest entry so that error messages are consistently | |
| 2141 // displayed across platforms. | |
| 2142 #if !defined(OS_CHROMEOS) | |
| 2143 plugins_.push_back(PluginInfo()); | |
| 2144 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str)); | |
| 2145 plugins_.back().is_public = is_public; | |
| 2146 #endif | |
| 2147 } | |
| 2148 } | |
| 2149 | |
| 2150 if (manifest_->HasKey(keys::kNaClModules)) { | |
| 2151 ListValue* list_value = NULL; | |
| 2152 if (!manifest_->GetList(keys::kNaClModules, &list_value)) { | |
| 2153 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 2154 return false; | |
| 2155 } | |
| 2156 | |
| 2157 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2158 DictionaryValue* module_value = NULL; | |
| 2159 std::string path_str; | |
| 2160 std::string mime_type; | |
| 2161 | |
| 2162 if (!list_value->GetDictionary(i, &module_value)) { | |
| 2163 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 2164 return false; | |
| 2165 } | |
| 2166 | |
| 2167 // Get nacl_modules[i].path. | |
| 2168 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) { | |
| 2169 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2170 errors::kInvalidNaClModulesPath, base::IntToString(i)); | |
| 2171 return false; | |
| 2172 } | |
| 2173 | |
| 2174 // Get nacl_modules[i].mime_type. | |
| 2175 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) { | |
| 2176 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2177 errors::kInvalidNaClModulesMIMEType, base::IntToString(i)); | |
| 2178 return false; | |
| 2179 } | |
| 2180 | |
| 2181 nacl_modules_.push_back(NaClModuleInfo()); | |
| 2182 nacl_modules_.back().url = GetResourceURL(path_str); | |
| 2183 nacl_modules_.back().mime_type = mime_type; | |
| 2184 } | |
| 2185 } | |
| 2186 | |
| 2187 // Initialize content scripts (optional). | |
| 2188 if (manifest_->HasKey(keys::kContentScripts)) { | |
| 2189 ListValue* list_value; | |
| 2190 if (!manifest_->GetList(keys::kContentScripts, &list_value)) { | |
| 2191 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList); | |
| 2192 return false; | |
| 2193 } | |
| 2194 | |
| 2195 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2196 DictionaryValue* content_script = NULL; | |
| 2197 if (!list_value->GetDictionary(i, &content_script)) { | |
| 2198 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2199 errors::kInvalidContentScript, base::IntToString(i)); | |
| 2200 return false; | |
| 2201 } | |
| 2202 | |
| 2203 UserScript script; | |
| 2204 if (!LoadUserScriptHelper(content_script, i, flags, error, &script)) | |
| 2205 return false; // Failed to parse script context definition. | |
| 2206 script.set_extension_id(id()); | |
| 2207 if (converted_from_user_script_) { | |
| 2208 script.set_emulate_greasemonkey(true); | |
| 2209 script.set_match_all_frames(true); // Greasemonkey matches all frames. | |
| 2210 } | |
| 2211 content_scripts_.push_back(script); | |
| 2212 } | |
| 2213 } | |
| 2214 | |
| 2215 // Initialize web accessible resources (optional). | |
| 2216 if (manifest_->HasKey(keys::kWebAccessibleResources)) { | |
| 2217 ListValue* list_value; | |
| 2218 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) { | |
| 2219 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList); | |
| 2220 return false; | |
| 2221 } | |
| 2222 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2223 std::string relative_path; | |
| 2224 if (!list_value->GetString(i, &relative_path)) { | |
| 2225 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2226 errors::kInvalidWebAccessibleResource, base::IntToString(i)); | |
| 2227 return false; | |
| 2228 } | |
| 2229 if (relative_path[0] != '/') | |
| 2230 relative_path = '/' + relative_path; | |
| 2231 web_accessible_resources_.insert(relative_path); | |
| 2232 } | |
| 2233 } | |
| 2234 | |
| 2235 // Initialize page action (optional). | |
| 2236 DictionaryValue* page_action_value = NULL; | |
| 2237 | |
| 2238 if (manifest_->HasKey(keys::kPageActions)) { | |
| 2239 ListValue* list_value = NULL; | |
| 2240 if (!manifest_->GetList(keys::kPageActions, &list_value)) { | |
| 2241 *error = ASCIIToUTF16(errors::kInvalidPageActionsList); | |
| 2242 return false; | |
| 2243 } | |
| 2244 | |
| 2245 size_t list_value_length = list_value->GetSize(); | |
| 2246 | |
| 2247 if (list_value_length == 0u) { | |
| 2248 // A list with zero items is allowed, and is equivalent to not having | |
| 2249 // a page_actions key in the manifest. Don't set |page_action_value|. | |
| 2250 } else if (list_value_length == 1u) { | |
| 2251 if (!list_value->GetDictionary(0, &page_action_value)) { | |
| 2252 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2253 return false; | |
| 2254 } | |
| 2255 } else { // list_value_length > 1u. | |
| 2256 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize); | |
| 2257 return false; | |
| 2258 } | |
| 2259 } else if (manifest_->HasKey(keys::kPageAction)) { | |
| 2260 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { | |
| 2261 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2262 return false; | |
| 2263 } | |
| 2264 } | |
| 2265 | |
| 2266 // If page_action_value is not NULL, then there was a valid page action. | |
| 2267 if (page_action_value) { | |
| 2268 page_action_.reset( | |
| 2269 LoadExtensionActionHelper(page_action_value, error)); | |
| 2270 if (!page_action_.get()) | |
| 2271 return false; // Failed to parse page action definition. | |
| 2272 } | |
| 2273 | |
| 2274 // Initialize browser action (optional). | |
| 2275 if (manifest_->HasKey(keys::kBrowserAction)) { | |
| 2276 DictionaryValue* browser_action_value = NULL; | |
| 2277 if (!manifest_->GetDictionary(keys::kBrowserAction, | |
| 2278 &browser_action_value)) { | |
| 2279 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); | |
| 2280 return false; | |
| 2281 } | |
| 2282 | |
| 2283 browser_action_.reset( | |
| 2284 LoadExtensionActionHelper(browser_action_value, error)); | |
| 2285 if (!browser_action_.get()) | |
| 2286 return false; // Failed to parse browser action definition. | |
| 2287 } | |
| 2288 | |
| 2289 // Initialize file browser actions (optional). | |
| 2290 if (manifest_->HasKey(keys::kFileBrowserHandlers)) { | |
| 2291 ListValue* file_browser_handlers_value = NULL; | |
| 2292 if (!manifest_->GetList(keys::kFileBrowserHandlers, | |
| 2293 &file_browser_handlers_value)) { | |
| 2294 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2295 return false; | |
| 2296 } | |
| 2297 | |
| 2298 file_browser_handlers_.reset( | |
| 2299 LoadFileBrowserHandlers(file_browser_handlers_value, error)); | |
| 2300 if (!file_browser_handlers_.get()) | |
| 2301 return false; // Failed to parse file browser actions definition. | |
| 2302 } | |
| 2303 | |
| 2304 // App isolation. | 2844 // App isolation. |
| 2305 if (api_permissions.count(ExtensionAPIPermission::kExperimental)) { | 2845 if (api_permissions.count(ExtensionAPIPermission::kExperimental) && |
| 2306 if (is_app() && !LoadAppIsolation(error)) | 2846 is_app() && !LoadAppIsolation(error)) |
| 2307 return false; | 2847 return false; |
| 2308 } | 2848 |
| 2309 | 2849 if (!LoadSharedFeatures(api_permissions, error)) |
| 2310 // Initialize options page url (optional). | 2850 return false; |
| 2311 if (manifest_->HasKey(keys::kOptionsPage)) { | 2851 |
| 2312 std::string options_str; | 2852 |
| 2313 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) { | 2853 if (!LoadExtensionFeatures(api_permissions, error)) |
| 2314 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | 2854 return false; |
| 2315 return false; | 2855 |
| 2316 } | 2856 if (!LoadThemeFeatures(error)) |
| 2317 | 2857 return false; |
| 2318 if (is_hosted_app()) { | |
| 2319 // hosted apps require an absolute URL. | |
| 2320 GURL options_url(options_str); | |
| 2321 if (!options_url.is_valid() || | |
| 2322 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) { | |
| 2323 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp); | |
| 2324 return false; | |
| 2325 } | |
| 2326 options_url_ = options_url; | |
| 2327 } else { | |
| 2328 GURL absolute(options_str); | |
| 2329 if (absolute.is_valid()) { | |
| 2330 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage); | |
| 2331 return false; | |
| 2332 } | |
| 2333 options_url_ = GetResourceURL(options_str); | |
| 2334 if (!options_url_.is_valid()) { | |
| 2335 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 2336 return false; | |
| 2337 } | |
| 2338 } | |
| 2339 } | |
| 2340 | |
| 2341 if (!LoadBackgroundScripts(error)) | |
| 2342 return false; | |
| 2343 | |
| 2344 if (!LoadBackgroundPage(api_permissions, error)) | |
| 2345 return false; | |
| 2346 | |
| 2347 if (!LoadBackgroundPersistent(api_permissions, error)) | |
| 2348 return false; | |
| 2349 | |
| 2350 if (!LoadBackgroundAllowJsAccess(api_permissions, error)) | |
| 2351 return false; | |
| 2352 | |
| 2353 if (manifest_->HasKey(keys::kDefaultLocale)) { | |
| 2354 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) || | |
| 2355 !l10n_util::IsValidLocaleSyntax(default_locale_)) { | |
| 2356 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale); | |
| 2357 return false; | |
| 2358 } | |
| 2359 } | |
| 2360 | |
| 2361 // Chrome URL overrides (optional) | |
| 2362 if (manifest_->HasKey(keys::kChromeURLOverrides)) { | |
| 2363 DictionaryValue* overrides = NULL; | |
| 2364 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) { | |
| 2365 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2366 return false; | |
| 2367 } | |
| 2368 | |
| 2369 // Validate that the overrides are all strings | |
| 2370 for (DictionaryValue::key_iterator iter = overrides->begin_keys(); | |
| 2371 iter != overrides->end_keys(); ++iter) { | |
| 2372 std::string page = *iter; | |
| 2373 std::string val; | |
| 2374 // Restrict override pages to a list of supported URLs. | |
| 2375 if ((page != chrome::kChromeUINewTabHost && | |
| 2376 #if defined(USE_VIRTUAL_KEYBOARD) | |
| 2377 page != chrome::kChromeUIKeyboardHost && | |
| 2378 #endif | |
| 2379 #if defined(OS_CHROMEOS) | |
| 2380 page != chrome::kChromeUIActivationMessageHost && | |
| 2381 #endif | |
| 2382 page != chrome::kChromeUIBookmarksHost && | |
| 2383 page != chrome::kChromeUIHistoryHost | |
| 2384 #if defined(FILE_MANAGER_EXTENSION) | |
| 2385 && | |
| 2386 !(location() == COMPONENT && | |
| 2387 page == chrome::kChromeUIFileManagerHost) | |
| 2388 #endif | |
| 2389 ) || | |
| 2390 !overrides->GetStringWithoutPathExpansion(*iter, &val)) { | |
| 2391 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2392 return false; | |
| 2393 } | |
| 2394 // Replace the entry with a fully qualified chrome-extension:// URL. | |
| 2395 chrome_url_overrides_[page] = GetResourceURL(val); | |
| 2396 } | |
| 2397 | |
| 2398 // An extension may override at most one page. | |
| 2399 if (overrides->size() > 1) { | |
| 2400 *error = ASCIIToUTF16(errors::kMultipleOverrides); | |
| 2401 return false; | |
| 2402 } | |
| 2403 } | |
| 2404 | |
| 2405 if (manifest_->HasKey(keys::kInputComponents)) { | |
| 2406 ListValue* list_value = NULL; | |
| 2407 if (!manifest_->GetList(keys::kInputComponents, &list_value)) { | |
| 2408 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 2409 return false; | |
| 2410 } | |
| 2411 | |
| 2412 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2413 DictionaryValue* module_value = NULL; | |
| 2414 std::string name_str; | |
| 2415 InputComponentType type; | |
| 2416 std::string id_str; | |
| 2417 std::string description_str; | |
| 2418 std::string language_str; | |
| 2419 std::set<std::string> layouts; | |
| 2420 std::string shortcut_keycode_str; | |
| 2421 bool shortcut_alt = false; | |
| 2422 bool shortcut_ctrl = false; | |
| 2423 bool shortcut_shift = false; | |
| 2424 | |
| 2425 if (!list_value->GetDictionary(i, &module_value)) { | |
| 2426 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 2427 return false; | |
| 2428 } | |
| 2429 | |
| 2430 // Get input_components[i].name. | |
| 2431 if (!module_value->GetString(keys::kName, &name_str)) { | |
| 2432 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2433 errors::kInvalidInputComponentName, base::IntToString(i)); | |
| 2434 return false; | |
| 2435 } | |
| 2436 | |
| 2437 // Get input_components[i].type. | |
| 2438 std::string type_str; | |
| 2439 if (module_value->GetString(keys::kType, &type_str)) { | |
| 2440 if (type_str == "ime") { | |
| 2441 type = INPUT_COMPONENT_TYPE_IME; | |
| 2442 } else if (type_str == "virtual_keyboard") { | |
| 2443 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { | |
| 2444 // Virtual Keyboards require the experimental flag. | |
| 2445 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2446 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2447 return false; | |
| 2448 } | |
| 2449 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD; | |
| 2450 } else { | |
| 2451 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2452 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2453 return false; | |
| 2454 } | |
| 2455 } else { | |
| 2456 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2457 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2458 return false; | |
| 2459 } | |
| 2460 | |
| 2461 // Get input_components[i].id. | |
| 2462 if (!module_value->GetString(keys::kId, &id_str)) { | |
| 2463 id_str = ""; | |
| 2464 } | |
| 2465 | |
| 2466 // Get input_components[i].description. | |
| 2467 if (!module_value->GetString(keys::kDescription, &description_str)) { | |
| 2468 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2469 errors::kInvalidInputComponentDescription, base::IntToString(i)); | |
| 2470 return false; | |
| 2471 } | |
| 2472 | |
| 2473 // Get input_components[i].language. | |
| 2474 if (!module_value->GetString(keys::kLanguage, &language_str)) { | |
| 2475 language_str = ""; | |
| 2476 } | |
| 2477 | |
| 2478 // Get input_components[i].layouts. | |
| 2479 ListValue* layouts_value = NULL; | |
| 2480 if (!module_value->GetList(keys::kLayouts, &layouts_value)) { | |
| 2481 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts); | |
| 2482 return false; | |
| 2483 } | |
| 2484 | |
| 2485 for (size_t j = 0; j < layouts_value->GetSize(); ++j) { | |
| 2486 std::string layout_name_str; | |
| 2487 if (!layouts_value->GetString(j, &layout_name_str)) { | |
| 2488 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2489 errors::kInvalidInputComponentLayoutName, base::IntToString(i), | |
| 2490 base::IntToString(j)); | |
| 2491 return false; | |
| 2492 } | |
| 2493 layouts.insert(layout_name_str); | |
| 2494 } | |
| 2495 | |
| 2496 if (module_value->HasKey(keys::kShortcutKey)) { | |
| 2497 DictionaryValue* shortcut_value = NULL; | |
| 2498 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) { | |
| 2499 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2500 errors::kInvalidInputComponentShortcutKey, base::IntToString(i)); | |
| 2501 return false; | |
| 2502 } | |
| 2503 | |
| 2504 // Get input_components[i].shortcut_keycode. | |
| 2505 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) { | |
| 2506 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2507 errors::kInvalidInputComponentShortcutKeycode, | |
| 2508 base::IntToString(i)); | |
| 2509 return false; | |
| 2510 } | |
| 2511 | |
| 2512 // Get input_components[i].shortcut_alt. | |
| 2513 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) { | |
| 2514 shortcut_alt = false; | |
| 2515 } | |
| 2516 | |
| 2517 // Get input_components[i].shortcut_ctrl. | |
| 2518 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) { | |
| 2519 shortcut_ctrl = false; | |
| 2520 } | |
| 2521 | |
| 2522 // Get input_components[i].shortcut_shift. | |
| 2523 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) { | |
| 2524 shortcut_shift = false; | |
| 2525 } | |
| 2526 } | |
| 2527 | |
| 2528 input_components_.push_back(InputComponentInfo()); | |
| 2529 input_components_.back().name = name_str; | |
| 2530 input_components_.back().type = type; | |
| 2531 input_components_.back().id = id_str; | |
| 2532 input_components_.back().description = description_str; | |
| 2533 input_components_.back().language = language_str; | |
| 2534 input_components_.back().layouts.insert(layouts.begin(), layouts.end()); | |
| 2535 input_components_.back().shortcut_keycode = shortcut_keycode_str; | |
| 2536 input_components_.back().shortcut_alt = shortcut_alt; | |
| 2537 input_components_.back().shortcut_ctrl = shortcut_ctrl; | |
| 2538 input_components_.back().shortcut_shift = shortcut_shift; | |
| 2539 } | |
| 2540 } | |
| 2541 | |
| 2542 if (manifest_->HasKey(keys::kOmnibox)) { | |
| 2543 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || | |
| 2544 omnibox_keyword_.empty()) { | |
| 2545 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword); | |
| 2546 return false; | |
| 2547 } | |
| 2548 } | |
| 2549 | |
| 2550 if (manifest_->HasKey(keys::kContentSecurityPolicy)) { | |
| 2551 std::string content_security_policy; | |
| 2552 if (!manifest_->GetString(keys::kContentSecurityPolicy, | |
| 2553 &content_security_policy)) { | |
| 2554 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2555 return false; | |
| 2556 } | |
| 2557 if (!ContentSecurityPolicyIsLegal(content_security_policy)) { | |
| 2558 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2559 return false; | |
| 2560 } | |
| 2561 if (manifest_version_ >= 2 && | |
| 2562 !ContentSecurityPolicyIsSecure(content_security_policy)) { | |
| 2563 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2564 return false; | |
| 2565 } | |
| 2566 | |
| 2567 content_security_policy_ = content_security_policy; | |
| 2568 } else if (manifest_version_ >= 2) { | |
| 2569 // Manifest version 2 introduced a default Content-Security-Policy. | |
| 2570 // TODO(abarth): Should we continue to let extensions override the | |
| 2571 // default Content-Security-Policy? | |
| 2572 content_security_policy_ = kDefaultContentSecurityPolicy; | |
| 2573 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_)); | |
| 2574 } | |
| 2575 | |
| 2576 // Initialize devtools page url (optional). | |
| 2577 if (manifest_->HasKey(keys::kDevToolsPage)) { | |
| 2578 std::string devtools_str; | |
| 2579 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) { | |
| 2580 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage); | |
| 2581 return false; | |
| 2582 } | |
| 2583 devtools_url_ = GetResourceURL(devtools_str); | |
| 2584 } | |
| 2585 | |
| 2586 // Initialize text-to-speech voices (optional). | |
| 2587 if (manifest_->HasKey(keys::kTtsEngine)) { | |
| 2588 DictionaryValue* tts_dict = NULL; | |
| 2589 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) { | |
| 2590 *error = ASCIIToUTF16(errors::kInvalidTts); | |
| 2591 return false; | |
| 2592 } | |
| 2593 | |
| 2594 if (tts_dict->HasKey(keys::kTtsVoices)) { | |
| 2595 ListValue* tts_voices = NULL; | |
| 2596 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) { | |
| 2597 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2598 return false; | |
| 2599 } | |
| 2600 | |
| 2601 for (size_t i = 0; i < tts_voices->GetSize(); i++) { | |
| 2602 DictionaryValue* one_tts_voice = NULL; | |
| 2603 if (!tts_voices->GetDictionary(i, &one_tts_voice)) { | |
| 2604 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2605 return false; | |
| 2606 } | |
| 2607 | |
| 2608 TtsVoice voice_data; | |
| 2609 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) { | |
| 2610 if (!one_tts_voice->GetString( | |
| 2611 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) { | |
| 2612 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName); | |
| 2613 return false; | |
| 2614 } | |
| 2615 } | |
| 2616 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) { | |
| 2617 if (!one_tts_voice->GetString( | |
| 2618 keys::kTtsVoicesLang, &voice_data.lang) || | |
| 2619 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) { | |
| 2620 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang); | |
| 2621 return false; | |
| 2622 } | |
| 2623 } | |
| 2624 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) { | |
| 2625 if (!one_tts_voice->GetString( | |
| 2626 keys::kTtsVoicesGender, &voice_data.gender) || | |
| 2627 (voice_data.gender != keys::kTtsGenderMale && | |
| 2628 voice_data.gender != keys::kTtsGenderFemale)) { | |
| 2629 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender); | |
| 2630 return false; | |
| 2631 } | |
| 2632 } | |
| 2633 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) { | |
| 2634 ListValue* event_types_list; | |
| 2635 if (!one_tts_voice->GetList( | |
| 2636 keys::kTtsVoicesEventTypes, &event_types_list)) { | |
| 2637 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2638 return false; | |
| 2639 } | |
| 2640 for (size_t i = 0; i < event_types_list->GetSize(); i++) { | |
| 2641 std::string event_type; | |
| 2642 if (!event_types_list->GetString(i, &event_type)) { | |
| 2643 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2644 return false; | |
| 2645 } | |
| 2646 if (event_type != keys::kTtsVoicesEventTypeEnd && | |
| 2647 event_type != keys::kTtsVoicesEventTypeError && | |
| 2648 event_type != keys::kTtsVoicesEventTypeMarker && | |
| 2649 event_type != keys::kTtsVoicesEventTypeSentence && | |
| 2650 event_type != keys::kTtsVoicesEventTypeStart && | |
| 2651 event_type != keys::kTtsVoicesEventTypeWord) { | |
| 2652 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2653 return false; | |
| 2654 } | |
| 2655 if (voice_data.event_types.find(event_type) != | |
| 2656 voice_data.event_types.end()) { | |
| 2657 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2658 return false; | |
| 2659 } | |
| 2660 voice_data.event_types.insert(event_type); | |
| 2661 } | |
| 2662 } | |
| 2663 | |
| 2664 tts_voices_.push_back(voice_data); | |
| 2665 } | |
| 2666 } | |
| 2667 } | |
| 2668 | |
| 2669 // Initialize web intents (optional). | |
| 2670 if (!LoadWebIntentServices(error)) | |
| 2671 return false; | |
| 2672 | |
| 2673 // Initialize incognito behavior. Apps default to split mode, extensions | |
| 2674 // default to spanning. | |
| 2675 incognito_split_mode_ = is_app(); | |
| 2676 if (manifest_->HasKey(keys::kIncognito)) { | |
| 2677 std::string value; | |
| 2678 if (!manifest_->GetString(keys::kIncognito, &value)) { | |
| 2679 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2680 return false; | |
| 2681 } | |
| 2682 if (value == values::kIncognitoSpanning) { | |
| 2683 incognito_split_mode_ = false; | |
| 2684 } else if (value == values::kIncognitoSplit) { | |
| 2685 incognito_split_mode_ = true; | |
| 2686 } else { | |
| 2687 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2688 return false; | |
| 2689 } | |
| 2690 } | |
| 2691 | |
| 2692 // Initialize offline-enabled status. Defaults to false. | |
| 2693 if (manifest_->HasKey(keys::kOfflineEnabled)) { | |
| 2694 if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { | |
| 2695 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled); | |
| 2696 return false; | |
| 2697 } | |
| 2698 } | |
| 2699 | |
| 2700 // Initialize requirements (optional). Not actually persisted (they're only | |
| 2701 // used by the store), but still validated. | |
| 2702 if (manifest_->HasKey(keys::kRequirements)) { | |
| 2703 DictionaryValue* requirements_value = NULL; | |
| 2704 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) { | |
| 2705 *error = ASCIIToUTF16(errors::kInvalidRequirements); | |
| 2706 return false; | |
| 2707 } | |
| 2708 | |
| 2709 for (DictionaryValue::key_iterator it = requirements_value->begin_keys(); | |
| 2710 it != requirements_value->end_keys(); ++it) { | |
| 2711 DictionaryValue* requirement_value; | |
| 2712 if (!requirements_value->GetDictionaryWithoutPathExpansion( | |
| 2713 *it, &requirement_value)) { | |
| 2714 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2715 errors::kInvalidRequirement, *it); | |
| 2716 return false; | |
| 2717 } | |
| 2718 } | |
| 2719 } | |
| 2720 | 2858 |
| 2721 if (HasMultipleUISurfaces()) { | 2859 if (HasMultipleUISurfaces()) { |
| 2722 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); | 2860 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); |
| 2723 return false; | 2861 return false; |
| 2724 } | 2862 } |
| 2725 | 2863 |
| 2726 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( | 2864 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( |
| 2727 this, api_permissions, host_permissions)); | 2865 this, api_permissions, host_permissions)); |
| 2728 required_permission_set_ = new ExtensionPermissionSet( | 2866 required_permission_set_ = new ExtensionPermissionSet( |
| 2729 this, api_permissions, host_permissions); | 2867 this, api_permissions, host_permissions); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2879 GURL Extension::GetIconURL(int size, | 3017 GURL Extension::GetIconURL(int size, |
| 2880 ExtensionIconSet::MatchType match_type) const { | 3018 ExtensionIconSet::MatchType match_type) const { |
| 2881 std::string path = icons().Get(size, match_type); | 3019 std::string path = icons().Get(size, match_type); |
| 2882 if (path.empty()) | 3020 if (path.empty()) |
| 2883 return GURL(); | 3021 return GURL(); |
| 2884 else | 3022 else |
| 2885 return GetResourceURL(path); | 3023 return GetResourceURL(path); |
| 2886 } | 3024 } |
| 2887 | 3025 |
| 2888 bool Extension::ParsePermissions(const char* key, | 3026 bool Extension::ParsePermissions(const char* key, |
| 2889 int flags, | |
| 2890 string16* error, | 3027 string16* error, |
| 2891 ExtensionAPIPermissionSet* api_permissions, | 3028 ExtensionAPIPermissionSet* api_permissions, |
| 2892 URLPatternSet* host_permissions) { | 3029 URLPatternSet* host_permissions) { |
| 2893 if (manifest_->HasKey(key)) { | 3030 if (manifest_->HasKey(key)) { |
| 2894 ListValue* permissions = NULL; | 3031 ListValue* permissions = NULL; |
| 2895 if (!manifest_->GetList(key, &permissions)) { | 3032 if (!manifest_->GetList(key, &permissions)) { |
| 2896 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 3033 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2897 errors::kInvalidPermissions, ""); | 3034 errors::kInvalidPermissions, ""); |
| 2898 return false; | 3035 return false; |
| 2899 } | 3036 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 2930 return false; | 3067 return false; |
| 2931 } | 3068 } |
| 2932 | 3069 |
| 2933 // The path component is not used for host permissions, so we force it | 3070 // The path component is not used for host permissions, so we force it |
| 2934 // to match all paths. | 3071 // to match all paths. |
| 2935 pattern.SetPath("/*"); | 3072 pattern.SetPath("/*"); |
| 2936 | 3073 |
| 2937 if (pattern.MatchesScheme(chrome::kFileScheme) && | 3074 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 2938 !CanExecuteScriptEverywhere()) { | 3075 !CanExecuteScriptEverywhere()) { |
| 2939 wants_file_access_ = true; | 3076 wants_file_access_ = true; |
| 2940 if (!(flags & ALLOW_FILE_ACCESS)) | 3077 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) |
| 2941 pattern.SetValidSchemes( | 3078 pattern.SetValidSchemes( |
| 2942 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 3079 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 2943 } | 3080 } |
| 2944 | 3081 |
| 2945 host_permissions->AddPattern(pattern); | 3082 host_permissions->AddPattern(pattern); |
| 2946 } | 3083 } |
| 2947 | 3084 |
| 2948 // If it's not a host permission, then it's probably an unknown API | 3085 // If it's not a host permission, then it's probably an unknown API |
| 2949 // permission. Do not throw an error so extensions can retain | 3086 // permission. Do not throw an error so extensions can retain |
| 2950 // backwards compatability (http://crbug.com/42742). | 3087 // backwards compatability (http://crbug.com/42742). |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3119 // extension with options. All other menu items like uninstall have | 3256 // extension with options. All other menu items like uninstall have |
| 3120 // no sense for component extensions. | 3257 // no sense for component extensions. |
| 3121 return location() != Extension::COMPONENT; | 3258 return location() != Extension::COMPONENT; |
| 3122 } | 3259 } |
| 3123 | 3260 |
| 3124 bool Extension::CanSpecifyAPIPermission( | 3261 bool Extension::CanSpecifyAPIPermission( |
| 3125 const ExtensionAPIPermission* permission, | 3262 const ExtensionAPIPermission* permission, |
| 3126 string16* error) const { | 3263 string16* error) const { |
| 3127 if (location() == Extension::COMPONENT) | 3264 if (location() == Extension::COMPONENT) |
| 3128 return true; | 3265 return true; |
| 3129 | |
| 3130 bool access_denied = false; | 3266 bool access_denied = false; |
| 3131 if (permission->HasWhitelist()) { | 3267 if (permission->HasWhitelist()) { |
| 3132 if (permission->IsWhitelisted(id())) | 3268 if (permission->IsWhitelisted(id())) |
| 3133 return true; | 3269 return true; |
| 3134 else | 3270 else |
| 3135 access_denied = true; | 3271 access_denied = true; |
| 3136 } else if (permission->is_component_only()) { | 3272 } else if (permission->is_component_only()) { |
| 3137 access_denied = true; | 3273 access_denied = true; |
| 3138 } | 3274 } |
| 3139 | 3275 |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3297 return SYNC_TYPE_APP; | 3433 return SYNC_TYPE_APP; |
| 3298 | 3434 |
| 3299 default: | 3435 default: |
| 3300 return SYNC_TYPE_NONE; | 3436 return SYNC_TYPE_NONE; |
| 3301 } | 3437 } |
| 3302 } | 3438 } |
| 3303 | 3439 |
| 3304 bool Extension::IsSyncable() const { | 3440 bool Extension::IsSyncable() const { |
| 3305 // TODO(akalin): Figure out if we need to allow some other types. | 3441 // TODO(akalin): Figure out if we need to allow some other types. |
| 3306 | 3442 |
| 3307 // We want to sync any extensions that are shown in the luancher because | 3443 // We want to sync any extensions that are shown in the launcher because |
| 3308 // their positions should sync. | 3444 // their positions should sync. |
| 3309 return location() == Extension::INTERNAL || | 3445 return location() == Extension::INTERNAL || |
| 3310 ShouldDisplayInLauncher(); | 3446 ShouldDisplayInLauncher(); |
| 3311 } | 3447 } |
| 3312 | 3448 |
| 3313 bool Extension::ShouldDisplayInLauncher() const { | 3449 bool Extension::ShouldDisplayInLauncher() const { |
| 3314 // All apps should be displayed on the NTP except for the Cloud Print App. | 3450 // All apps should be displayed on the NTP except for the Cloud Print App. |
| 3315 return is_app() && id() != extension_misc::kCloudPrintAppId; | 3451 return is_app() && id() != extension_misc::kCloudPrintAppId; |
| 3316 } | 3452 } |
| 3317 | 3453 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3350 already_disabled(false), | 3486 already_disabled(false), |
| 3351 extension(extension) {} | 3487 extension(extension) {} |
| 3352 | 3488 |
| 3353 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3489 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
| 3354 const Extension* extension, | 3490 const Extension* extension, |
| 3355 const ExtensionPermissionSet* permissions, | 3491 const ExtensionPermissionSet* permissions, |
| 3356 Reason reason) | 3492 Reason reason) |
| 3357 : reason(reason), | 3493 : reason(reason), |
| 3358 extension(extension), | 3494 extension(extension), |
| 3359 permissions(permissions) {} | 3495 permissions(permissions) {} |
| OLD | NEW |