| 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) || |
| 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::LoadWebIntentAction(const std::string& action_name, | 1351 !LoadWebIntentServices(error)) |
| 1328 const DictionaryValue& intent_service, | 1352 return false; |
| 1329 string16* error) { | 1353 |
| 1330 DCHECK(error); | 1354 return true; |
| 1331 webkit_glue::WebIntentServiceData service; | 1355 } |
| 1332 std::string value; | 1356 |
| 1333 | 1357 bool Extension::LoadVersion(string16* error) { |
| 1334 service.action = UTF8ToUTF16(action_name); | 1358 std::string version_str; |
| 1335 | 1359 if (!manifest_->GetString(keys::kVersion, &version_str)) { |
| 1336 ListValue* mime_types = NULL; | 1360 *error = ASCIIToUTF16(errors::kInvalidVersion); |
| 1337 if (!intent_service.HasKey(keys::kIntentType) || | 1361 return false; |
| 1338 !intent_service.GetList(keys::kIntentType, &mime_types) || | 1362 } |
| 1339 mime_types->GetSize() == 0) { | 1363 version_.reset(Version::GetVersionFromString(version_str)); |
| 1364 if (!version_.get() || |
| 1365 version_->components().size() > 4) { |
| 1366 *error = ASCIIToUTF16(errors::kInvalidVersion); |
| 1367 return false; |
| 1368 } |
| 1369 return true; |
| 1370 } |
| 1371 |
| 1372 bool Extension::LoadManifestVersion(string16* error) { |
| 1373 // Get the original value out of the dictionary so that we can validate it |
| 1374 // more strictly. |
| 1375 if (manifest_->value()->HasKey(keys::kManifestVersion)) { |
| 1376 int manifest_version = 1; |
| 1377 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) || |
| 1378 manifest_version < 1) { |
| 1379 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); |
| 1380 return false; |
| 1381 } |
| 1382 } |
| 1383 |
| 1384 manifest_version_ = manifest_->GetManifestVersion(); |
| 1385 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION && |
| 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)) { |
| 1340 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1401 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1341 errors::kInvalidIntentType, action_name); | 1402 errors::kInvalidHomepageURL, ""); |
| 1342 return false; | 1403 return false; |
| 1343 } | 1404 } |
| 1344 | 1405 homepage_url_ = GURL(tmp); |
| 1345 std::string href; | 1406 if (!homepage_url_.is_valid() || |
| 1346 if (intent_service.HasKey(keys::kIntentPath)) { | 1407 (!homepage_url_.SchemeIs("http") && |
| 1347 if (!intent_service.GetString(keys::kIntentPath, &href)) { | 1408 !homepage_url_.SchemeIs("https"))) { |
| 1348 *error = ASCIIToUTF16(errors::kInvalidIntentHref); | 1409 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1349 return false; | 1410 errors::kInvalidHomepageURL, tmp); |
| 1350 } | 1411 return false; |
| 1351 } | 1412 } |
| 1352 | 1413 return true; |
| 1353 if (intent_service.HasKey(keys::kIntentHref)) { | 1414 } |
| 1354 if (!href.empty()) { | 1415 |
| 1355 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1416 bool Extension::LoadUpdateURL(string16* error) { |
| 1356 errors::kInvalidIntentHrefOldAndNewKey, action_name, | 1417 if (!manifest_->HasKey(keys::kUpdateURL)) |
| 1357 keys::kIntentPath, keys::kIntentHref); | 1418 return true; |
| 1358 return false; | 1419 std::string tmp; |
| 1359 } | 1420 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) { |
| 1360 if (!intent_service.GetString(keys::kIntentHref, &href)) { | 1421 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1361 *error = ASCIIToUTF16(errors::kInvalidIntentHref); | 1422 errors::kInvalidUpdateURL, ""); |
| 1362 return false; | 1423 return false; |
| 1363 } | 1424 } |
| 1364 } | 1425 update_url_ = GURL(tmp); |
| 1365 | 1426 if (!update_url_.is_valid() || |
| 1366 if (!href.empty()) { | 1427 update_url_.has_ref()) { |
| 1367 GURL service_url(href); | 1428 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1368 if (is_hosted_app()) { | 1429 errors::kInvalidUpdateURL, tmp); |
| 1369 // Hosted apps require an absolute URL for intents. | 1430 return false; |
| 1370 if (!service_url.is_valid() || | 1431 } |
| 1371 !(web_extent().MatchesURL(service_url))) { | 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)) { |
| 1372 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1449 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1373 errors::kInvalidIntentPageInHostedApp, action_name); | 1450 errors::kInvalidIconPath, key); |
| 1374 return false; | 1451 return false; |
| 1375 } | 1452 } |
| 1376 service.service_url = service_url; | 1453 |
| 1377 } else { | 1454 if (!icon_path.empty() && icon_path[0] == '/') |
| 1378 // We do not allow absolute intent URLs in non-hosted apps. | 1455 icon_path = icon_path.substr(1); |
| 1379 if (service_url.is_valid()) { | 1456 |
| 1380 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | 1457 if (icon_path.empty()) { |
| 1381 errors::kCannotAccessPage, href); | 1458 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1459 errors::kInvalidIconPath, key); |
| 1382 return false; | 1460 return false; |
| 1383 } | 1461 } |
| 1384 service.service_url = GetResourceURL(href); | 1462 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path); |
| 1385 } | 1463 } |
| 1386 } | 1464 } |
| 1387 | 1465 return true; |
| 1388 if (intent_service.HasKey(keys::kIntentTitle) && | 1466 } |
| 1389 !intent_service.GetString(keys::kIntentTitle, &service.title)) { | 1467 |
| 1390 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | 1468 bool Extension::LoadCommands(string16* error) { |
| 1391 return false; | 1469 if (manifest_->HasKey(keys::kCommands)) { |
| 1392 } | 1470 DictionaryValue* commands = NULL; |
| 1393 | 1471 if (!manifest_->GetDictionary(keys::kCommands, &commands)) { |
| 1394 if (intent_service.HasKey(keys::kIntentDisposition)) { | 1472 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); |
| 1395 if (!intent_service.GetString(keys::kIntentDisposition, &value) || | 1473 return false; |
| 1396 (value != values::kIntentDispositionWindow && | 1474 } |
| 1397 value != values::kIntentDispositionInline)) { | 1475 |
| 1398 *error = ASCIIToUTF16(errors::kInvalidIntentDisposition); | 1476 int command_index = 0; |
| 1399 return false; | 1477 for (DictionaryValue::key_iterator iter = commands->begin_keys(); |
| 1400 } | 1478 iter != commands->end_keys(); ++iter) { |
| 1401 if (value == values::kIntentDispositionInline) { | 1479 ++command_index; |
| 1402 service.disposition = | 1480 |
| 1403 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; | 1481 DictionaryValue* command = NULL; |
| 1404 } else { | 1482 if (!commands->GetDictionary(*iter, &command)) { |
| 1405 service.disposition = | 1483 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1406 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW; | 1484 errors::kInvalidKeyBindingDictionary, |
| 1407 } | 1485 base::IntToString(command_index)); |
| 1408 } | |
| 1409 | |
| 1410 for (size_t i = 0; i < mime_types->GetSize(); ++i) { | |
| 1411 if (!mime_types->GetString(i, &service.type)) { | |
| 1412 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1413 errors::kInvalidIntentTypeElement, action_name, | |
| 1414 std::string(base::IntToString(i))); | |
| 1415 return false; | |
| 1416 } | |
| 1417 intents_services_.push_back(service); | |
| 1418 } | |
| 1419 return true; | |
| 1420 } | |
| 1421 | |
| 1422 bool Extension::LoadWebIntentServices(string16* error) { | |
| 1423 DCHECK(error); | |
| 1424 | |
| 1425 if (!manifest_->HasKey(keys::kIntents)) | |
| 1426 return true; | |
| 1427 | |
| 1428 DictionaryValue* all_services = NULL; | |
| 1429 if (!manifest_->GetDictionary(keys::kIntents, &all_services)) { | |
| 1430 *error = ASCIIToUTF16(errors::kInvalidIntents); | |
| 1431 return false; | |
| 1432 } | |
| 1433 | |
| 1434 for (DictionaryValue::key_iterator iter(all_services->begin_keys()); | |
| 1435 iter != all_services->end_keys(); ++iter) { | |
| 1436 // Any entry in the intents dictionary can either have a list of | |
| 1437 // dictionaries, or just a single dictionary attached to that. Try | |
| 1438 // lists first, fall back to single dictionary. | |
| 1439 ListValue* service_list = NULL; | |
| 1440 DictionaryValue* one_service = NULL; | |
| 1441 if (all_services->GetListWithoutPathExpansion(*iter, &service_list)) { | |
| 1442 for (size_t i = 0; i < service_list->GetSize(); ++i) { | |
| 1443 if (!service_list->GetDictionary(i, &one_service)) { | |
| 1444 *error = ASCIIToUTF16(errors::kInvalidIntent); | |
| 1445 return false; | |
| 1446 } | |
| 1447 if (!LoadWebIntentAction(*iter, *one_service, error)) | |
| 1448 return false; | |
| 1449 } | |
| 1450 } else { | |
| 1451 if (!all_services->GetDictionaryWithoutPathExpansion(*iter, | |
| 1452 &one_service)) { | |
| 1453 *error = ASCIIToUTF16(errors::kInvalidIntent); | |
| 1454 return false; | 1486 return false; |
| 1455 } | 1487 } |
| 1456 if (!LoadWebIntentAction(*iter, *one_service, error)) | 1488 |
| 1489 ExtensionKeybinding binding; |
| 1490 if (!binding.Parse(command, *iter, command_index, error)) |
| 1491 return false; // |error| already set. |
| 1492 |
| 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)); |
| 1457 return false; | 1528 return false; |
| 1458 } | 1529 } |
| 1459 } | 1530 } |
| 1460 return true; | 1531 |
| 1461 } | 1532 // We don't allow extension plugins to run on Chrome OS. We still |
| 1462 | 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 |
| 1463 bool Extension::LoadBackgroundScripts(string16* error) { | 1687 bool Extension::LoadBackgroundScripts(string16* error) { |
| 1464 Value* background_scripts_value = NULL; | 1688 Value* background_scripts_value = NULL; |
| 1465 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) | 1689 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) |
| 1466 return true; | 1690 return true; |
| 1467 | 1691 |
| 1468 CHECK(background_scripts_value); | 1692 CHECK(background_scripts_value); |
| 1469 if (background_scripts_value->GetType() != Value::TYPE_LIST) { | 1693 if (background_scripts_value->GetType() != Value::TYPE_LIST) { |
| 1470 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); | 1694 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); |
| 1471 return false; | 1695 return false; |
| 1472 } | 1696 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1550 } | 1774 } |
| 1551 | 1775 |
| 1552 if (!has_background_page()) { | 1776 if (!has_background_page()) { |
| 1553 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); | 1777 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); |
| 1554 return false; | 1778 return false; |
| 1555 } | 1779 } |
| 1556 | 1780 |
| 1557 return true; | 1781 return true; |
| 1558 } | 1782 } |
| 1559 | 1783 |
| 1560 bool Extension::LoadBackgroundAllowJsAccess( | 1784 bool Extension::LoadBackgroundAllowJSAccess( |
| 1561 const ExtensionAPIPermissionSet& api_permissions, | 1785 const ExtensionAPIPermissionSet& api_permissions, |
| 1562 string16* error) { | 1786 string16* error) { |
| 1563 Value* allow_js_access = NULL; | 1787 Value* allow_js_access = NULL; |
| 1564 if (!manifest_->Get(keys::kBackgroundAllowJsAccess, &allow_js_access)) | 1788 if (!manifest_->Get(keys::kBackgroundAllowJsAccess, &allow_js_access)) |
| 1565 return true; | 1789 return true; |
| 1566 | 1790 |
| 1567 if (!allow_js_access->IsType(Value::TYPE_BOOLEAN) || | 1791 if (!allow_js_access->IsType(Value::TYPE_BOOLEAN) || |
| 1568 !allow_js_access->GetAsBoolean(&allow_background_js_access_)) { | 1792 !allow_js_access->GetAsBoolean(&allow_background_js_access_)) { |
| 1569 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess); | 1793 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess); |
| 1570 return false; | 1794 return false; |
| 1571 } | 1795 } |
| 1572 | 1796 |
| 1573 if (!has_background_page()) { | 1797 if (!has_background_page()) { |
| 1574 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccessNoPage); | 1798 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccessNoPage); |
| 1575 return false; | 1799 return false; |
| 1576 } | 1800 } |
| 1577 | 1801 |
| 1578 return true; | 1802 return true; |
| 1579 } | 1803 } |
| 1580 | 1804 |
| 1805 bool Extension::LoadWebIntentAction(const std::string& action_name, |
| 1806 const DictionaryValue& intent_service, |
| 1807 string16* error) { |
| 1808 DCHECK(error); |
| 1809 webkit_glue::WebIntentServiceData service; |
| 1810 std::string value; |
| 1811 |
| 1812 service.action = UTF8ToUTF16(action_name); |
| 1813 |
| 1814 ListValue* mime_types = NULL; |
| 1815 if (!intent_service.HasKey(keys::kIntentType) || |
| 1816 !intent_service.GetList(keys::kIntentType, &mime_types) || |
| 1817 mime_types->GetSize() == 0) { |
| 1818 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1819 errors::kInvalidIntentType, action_name); |
| 1820 return false; |
| 1821 } |
| 1822 |
| 1823 std::string href; |
| 1824 if (intent_service.HasKey(keys::kIntentPath)) { |
| 1825 if (!intent_service.GetString(keys::kIntentPath, &href)) { |
| 1826 *error = ASCIIToUTF16(errors::kInvalidIntentHref); |
| 1827 return false; |
| 1828 } |
| 1829 } |
| 1830 |
| 1831 if (intent_service.HasKey(keys::kIntentHref)) { |
| 1832 if (!href.empty()) { |
| 1833 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1834 errors::kInvalidIntentHrefOldAndNewKey, action_name, |
| 1835 keys::kIntentPath, keys::kIntentHref); |
| 1836 return false; |
| 1837 } |
| 1838 if (!intent_service.GetString(keys::kIntentHref, &href)) { |
| 1839 *error = ASCIIToUTF16(errors::kInvalidIntentHref); |
| 1840 return false; |
| 1841 } |
| 1842 } |
| 1843 |
| 1844 if (!href.empty()) { |
| 1845 GURL service_url(href); |
| 1846 if (is_hosted_app()) { |
| 1847 // Hosted apps require an absolute URL for intents. |
| 1848 if (!service_url.is_valid() || |
| 1849 !(web_extent().MatchesURL(service_url))) { |
| 1850 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1851 errors::kInvalidIntentPageInHostedApp, action_name); |
| 1852 return false; |
| 1853 } |
| 1854 service.service_url = service_url; |
| 1855 } else { |
| 1856 // We do not allow absolute intent URLs in non-hosted apps. |
| 1857 if (service_url.is_valid()) { |
| 1858 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1859 errors::kCannotAccessPage, href); |
| 1860 return false; |
| 1861 } |
| 1862 service.service_url = GetResourceURL(href); |
| 1863 } |
| 1864 } |
| 1865 |
| 1866 if (intent_service.HasKey(keys::kIntentTitle) && |
| 1867 !intent_service.GetString(keys::kIntentTitle, &service.title)) { |
| 1868 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); |
| 1869 return false; |
| 1870 } |
| 1871 |
| 1872 if (intent_service.HasKey(keys::kIntentDisposition)) { |
| 1873 if (!intent_service.GetString(keys::kIntentDisposition, &value) || |
| 1874 (value != values::kIntentDispositionWindow && |
| 1875 value != values::kIntentDispositionInline)) { |
| 1876 *error = ASCIIToUTF16(errors::kInvalidIntentDisposition); |
| 1877 return false; |
| 1878 } |
| 1879 if (value == values::kIntentDispositionInline) { |
| 1880 service.disposition = |
| 1881 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; |
| 1882 } else { |
| 1883 service.disposition = |
| 1884 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW; |
| 1885 } |
| 1886 } |
| 1887 |
| 1888 for (size_t i = 0; i < mime_types->GetSize(); ++i) { |
| 1889 if (!mime_types->GetString(i, &service.type)) { |
| 1890 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1891 errors::kInvalidIntentTypeElement, action_name, |
| 1892 std::string(base::IntToString(i))); |
| 1893 return false; |
| 1894 } |
| 1895 intents_services_.push_back(service); |
| 1896 } |
| 1897 return true; |
| 1898 } |
| 1899 |
| 1900 bool Extension::LoadWebIntentServices(string16* error) { |
| 1901 DCHECK(error); |
| 1902 |
| 1903 if (!manifest_->HasKey(keys::kIntents)) |
| 1904 return true; |
| 1905 |
| 1906 DictionaryValue* all_services = NULL; |
| 1907 if (!manifest_->GetDictionary(keys::kIntents, &all_services)) { |
| 1908 *error = ASCIIToUTF16(errors::kInvalidIntents); |
| 1909 return false; |
| 1910 } |
| 1911 |
| 1912 for (DictionaryValue::key_iterator iter(all_services->begin_keys()); |
| 1913 iter != all_services->end_keys(); ++iter) { |
| 1914 // Any entry in the intents dictionary can either have a list of |
| 1915 // dictionaries, or just a single dictionary attached to that. Try |
| 1916 // lists first, fall back to single dictionary. |
| 1917 ListValue* service_list = NULL; |
| 1918 DictionaryValue* one_service = NULL; |
| 1919 if (all_services->GetListWithoutPathExpansion(*iter, &service_list)) { |
| 1920 for (size_t i = 0; i < service_list->GetSize(); ++i) { |
| 1921 if (!service_list->GetDictionary(i, &one_service)) { |
| 1922 *error = ASCIIToUTF16(errors::kInvalidIntent); |
| 1923 return false; |
| 1924 } |
| 1925 if (!LoadWebIntentAction(*iter, *one_service, error)) |
| 1926 return false; |
| 1927 } |
| 1928 } else { |
| 1929 if (!all_services->GetDictionaryWithoutPathExpansion(*iter, |
| 1930 &one_service)) { |
| 1931 *error = ASCIIToUTF16(errors::kInvalidIntent); |
| 1932 return false; |
| 1933 } |
| 1934 if (!LoadWebIntentAction(*iter, *one_service, error)) |
| 1935 return false; |
| 1936 } |
| 1937 } |
| 1938 return true; |
| 1939 } |
| 1940 bool Extension::LoadExtensionFeatures( |
| 1941 const ExtensionAPIPermissionSet& api_permissions, |
| 1942 string16* error) { |
| 1943 if (manifest_->HasKey(keys::kConvertedFromUserScript)) |
| 1944 manifest_->GetBoolean(keys::kConvertedFromUserScript, |
| 1945 &converted_from_user_script_); |
| 1946 |
| 1947 if (!LoadDevToolsPage(error) || |
| 1948 !LoadInputComponents(api_permissions, error) || |
| 1949 !LoadContentScripts(error) || |
| 1950 !LoadPageAction(error) || |
| 1951 !LoadBrowserAction(error) || |
| 1952 !LoadFileBrowserHandlers(error) || |
| 1953 !LoadChromeURLOverrides(error) || |
| 1954 !LoadOmnibox(error) || |
| 1955 !LoadTextToSpeechVoices(error) || |
| 1956 !LoadIncognitoMode(error) || |
| 1957 !LoadContentSecurityPolicy(error)) |
| 1958 return false; |
| 1959 |
| 1960 return true; |
| 1961 } |
| 1962 |
| 1963 bool Extension::LoadDevToolsPage(string16* error) { |
| 1964 if (!manifest_->HasKey(keys::kDevToolsPage)) |
| 1965 return true; |
| 1966 std::string devtools_str; |
| 1967 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) { |
| 1968 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage); |
| 1969 return false; |
| 1970 } |
| 1971 devtools_url_ = GetResourceURL(devtools_str); |
| 1972 return true; |
| 1973 } |
| 1974 |
| 1975 bool Extension::LoadInputComponents( |
| 1976 const ExtensionAPIPermissionSet& api_permissions, |
| 1977 string16* error) { |
| 1978 if (!manifest_->HasKey(keys::kInputComponents)) |
| 1979 return true; |
| 1980 ListValue* list_value = NULL; |
| 1981 if (!manifest_->GetList(keys::kInputComponents, &list_value)) { |
| 1982 *error = ASCIIToUTF16(errors::kInvalidInputComponents); |
| 1983 return false; |
| 1984 } |
| 1985 |
| 1986 for (size_t i = 0; i < list_value->GetSize(); ++i) { |
| 1987 DictionaryValue* module_value = NULL; |
| 1988 std::string name_str; |
| 1989 InputComponentType type; |
| 1990 std::string id_str; |
| 1991 std::string description_str; |
| 1992 std::string language_str; |
| 1993 std::set<std::string> layouts; |
| 1994 std::string shortcut_keycode_str; |
| 1995 bool shortcut_alt = false; |
| 1996 bool shortcut_ctrl = false; |
| 1997 bool shortcut_shift = false; |
| 1998 |
| 1999 if (!list_value->GetDictionary(i, &module_value)) { |
| 2000 *error = ASCIIToUTF16(errors::kInvalidInputComponents); |
| 2001 return false; |
| 2002 } |
| 2003 |
| 2004 // Get input_components[i].name. |
| 2005 if (!module_value->GetString(keys::kName, &name_str)) { |
| 2006 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2007 errors::kInvalidInputComponentName, base::IntToString(i)); |
| 2008 return false; |
| 2009 } |
| 2010 |
| 2011 // Get input_components[i].type. |
| 2012 std::string type_str; |
| 2013 if (module_value->GetString(keys::kType, &type_str)) { |
| 2014 if (type_str == "ime") { |
| 2015 type = INPUT_COMPONENT_TYPE_IME; |
| 2016 } else if (type_str == "virtual_keyboard") { |
| 2017 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { |
| 2018 // Virtual Keyboards require the experimental flag. |
| 2019 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2020 errors::kInvalidInputComponentType, base::IntToString(i)); |
| 2021 return false; |
| 2022 } |
| 2023 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD; |
| 2024 } else { |
| 2025 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2026 errors::kInvalidInputComponentType, base::IntToString(i)); |
| 2027 return false; |
| 2028 } |
| 2029 } else { |
| 2030 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2031 errors::kInvalidInputComponentType, base::IntToString(i)); |
| 2032 return false; |
| 2033 } |
| 2034 |
| 2035 // Get input_components[i].id. |
| 2036 if (!module_value->GetString(keys::kId, &id_str)) { |
| 2037 id_str = ""; |
| 2038 } |
| 2039 |
| 2040 // Get input_components[i].description. |
| 2041 if (!module_value->GetString(keys::kDescription, &description_str)) { |
| 2042 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2043 errors::kInvalidInputComponentDescription, base::IntToString(i)); |
| 2044 return false; |
| 2045 } |
| 2046 // Get input_components[i].language. |
| 2047 if (!module_value->GetString(keys::kLanguage, &language_str)) { |
| 2048 language_str = ""; |
| 2049 } |
| 2050 |
| 2051 // Get input_components[i].layouts. |
| 2052 ListValue* layouts_value = NULL; |
| 2053 if (!module_value->GetList(keys::kLayouts, &layouts_value)) { |
| 2054 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts); |
| 2055 return false; |
| 2056 } |
| 2057 |
| 2058 for (size_t j = 0; j < layouts_value->GetSize(); ++j) { |
| 2059 std::string layout_name_str; |
| 2060 if (!layouts_value->GetString(j, &layout_name_str)) { |
| 2061 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2062 errors::kInvalidInputComponentLayoutName, base::IntToString(i), |
| 2063 base::IntToString(j)); |
| 2064 return false; |
| 2065 } |
| 2066 layouts.insert(layout_name_str); |
| 2067 } |
| 2068 |
| 2069 if (module_value->HasKey(keys::kShortcutKey)) { |
| 2070 DictionaryValue* shortcut_value = NULL; |
| 2071 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) { |
| 2072 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2073 errors::kInvalidInputComponentShortcutKey, base::IntToString(i)); |
| 2074 return false; |
| 2075 } |
| 2076 |
| 2077 // Get input_components[i].shortcut_keycode. |
| 2078 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) { |
| 2079 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2080 errors::kInvalidInputComponentShortcutKeycode, |
| 2081 base::IntToString(i)); |
| 2082 return false; |
| 2083 } |
| 2084 |
| 2085 // Get input_components[i].shortcut_alt. |
| 2086 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) { |
| 2087 shortcut_alt = false; |
| 2088 } |
| 2089 |
| 2090 // Get input_components[i].shortcut_ctrl. |
| 2091 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) { |
| 2092 shortcut_ctrl = false; |
| 2093 } |
| 2094 |
| 2095 // Get input_components[i].shortcut_shift. |
| 2096 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) { |
| 2097 shortcut_shift = false; |
| 2098 } |
| 2099 } |
| 2100 |
| 2101 input_components_.push_back(InputComponentInfo()); |
| 2102 input_components_.back().name = name_str; |
| 2103 input_components_.back().type = type; |
| 2104 input_components_.back().id = id_str; |
| 2105 input_components_.back().description = description_str; |
| 2106 input_components_.back().language = language_str; |
| 2107 input_components_.back().layouts.insert(layouts.begin(), layouts.end()); |
| 2108 input_components_.back().shortcut_keycode = shortcut_keycode_str; |
| 2109 input_components_.back().shortcut_alt = shortcut_alt; |
| 2110 input_components_.back().shortcut_ctrl = shortcut_ctrl; |
| 2111 input_components_.back().shortcut_shift = shortcut_shift; |
| 2112 } |
| 2113 |
| 2114 return true; |
| 2115 } |
| 2116 |
| 2117 bool Extension::LoadContentScripts(string16* error) { |
| 2118 if (!manifest_->HasKey(keys::kContentScripts)) |
| 2119 return true; |
| 2120 ListValue* list_value; |
| 2121 if (!manifest_->GetList(keys::kContentScripts, &list_value)) { |
| 2122 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList); |
| 2123 return false; |
| 2124 } |
| 2125 |
| 2126 for (size_t i = 0; i < list_value->GetSize(); ++i) { |
| 2127 DictionaryValue* content_script = NULL; |
| 2128 if (!list_value->GetDictionary(i, &content_script)) { |
| 2129 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2130 errors::kInvalidContentScript, base::IntToString(i)); |
| 2131 return false; |
| 2132 } |
| 2133 |
| 2134 UserScript script; |
| 2135 if (!LoadUserScriptHelper(content_script, i, error, &script)) |
| 2136 return false; // Failed to parse script context definition. |
| 2137 script.set_extension_id(id()); |
| 2138 if (converted_from_user_script_) { |
| 2139 script.set_emulate_greasemonkey(true); |
| 2140 script.set_match_all_frames(true); // Greasemonkey matches all frames. |
| 2141 } |
| 2142 content_scripts_.push_back(script); |
| 2143 } |
| 2144 return true; |
| 2145 } |
| 2146 |
| 2147 bool Extension::LoadPageAction(string16* error) { |
| 2148 DictionaryValue* page_action_value = NULL; |
| 2149 |
| 2150 if (manifest_->HasKey(keys::kPageActions)) { |
| 2151 ListValue* list_value = NULL; |
| 2152 if (!manifest_->GetList(keys::kPageActions, &list_value)) { |
| 2153 *error = ASCIIToUTF16(errors::kInvalidPageActionsList); |
| 2154 return false; |
| 2155 } |
| 2156 |
| 2157 size_t list_value_length = list_value->GetSize(); |
| 2158 |
| 2159 if (list_value_length == 0u) { |
| 2160 // A list with zero items is allowed, and is equivalent to not having |
| 2161 // a page_actions key in the manifest. Don't set |page_action_value|. |
| 2162 } else if (list_value_length == 1u) { |
| 2163 if (!list_value->GetDictionary(0, &page_action_value)) { |
| 2164 *error = ASCIIToUTF16(errors::kInvalidPageAction); |
| 2165 return false; |
| 2166 } |
| 2167 } else { // list_value_length > 1u. |
| 2168 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize); |
| 2169 return false; |
| 2170 } |
| 2171 } else if (manifest_->HasKey(keys::kPageAction)) { |
| 2172 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { |
| 2173 *error = ASCIIToUTF16(errors::kInvalidPageAction); |
| 2174 return false; |
| 2175 } |
| 2176 } |
| 2177 |
| 2178 // If page_action_value is not NULL, then there was a valid page action. |
| 2179 if (page_action_value) { |
| 2180 page_action_.reset( |
| 2181 LoadExtensionActionHelper(page_action_value, error)); |
| 2182 if (!page_action_.get()) |
| 2183 return false; // Failed to parse page action definition. |
| 2184 } |
| 2185 |
| 2186 return true; |
| 2187 } |
| 2188 |
| 2189 bool Extension::LoadBrowserAction(string16* error) { |
| 2190 if (!manifest_->HasKey(keys::kBrowserAction)) |
| 2191 return true; |
| 2192 DictionaryValue* browser_action_value = NULL; |
| 2193 if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) { |
| 2194 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); |
| 2195 return false; |
| 2196 } |
| 2197 |
| 2198 browser_action_.reset( |
| 2199 LoadExtensionActionHelper(browser_action_value, error)); |
| 2200 if (!browser_action_.get()) |
| 2201 return false; // Failed to parse browser action definition. |
| 2202 return true; |
| 2203 } |
| 2204 |
| 2205 bool Extension::LoadFileBrowserHandlers(string16* error) { |
| 2206 if (!manifest_->HasKey(keys::kFileBrowserHandlers)) |
| 2207 return true; |
| 2208 ListValue* file_browser_handlers_value = NULL; |
| 2209 if (!manifest_->GetList(keys::kFileBrowserHandlers, |
| 2210 &file_browser_handlers_value)) { |
| 2211 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); |
| 2212 return false; |
| 2213 } |
| 2214 file_browser_handlers_.reset( |
| 2215 LoadFileBrowserHandlersHelper(file_browser_handlers_value, error)); |
| 2216 if (!file_browser_handlers_.get()) |
| 2217 return false; // Failed to parse file browser actions definition. |
| 2218 return true; |
| 2219 } |
| 2220 |
| 2221 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlersHelper( |
| 2222 const ListValue* extension_actions, string16* error) { |
| 2223 scoped_ptr<FileBrowserHandlerList> result( |
| 2224 new FileBrowserHandlerList()); |
| 2225 for (ListValue::const_iterator iter = extension_actions->begin(); |
| 2226 iter != extension_actions->end(); |
| 2227 ++iter) { |
| 2228 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) { |
| 2229 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); |
| 2230 return NULL; |
| 2231 } |
| 2232 scoped_ptr<FileBrowserHandler> action( |
| 2233 LoadFileBrowserHandler( |
| 2234 reinterpret_cast<DictionaryValue*>(*iter), error)); |
| 2235 if (!action.get()) |
| 2236 return NULL; // Failed to parse file browser action definition. |
| 2237 result->push_back(linked_ptr<FileBrowserHandler>(action.release())); |
| 2238 } |
| 2239 return result.release(); |
| 2240 } |
| 2241 |
| 2242 FileBrowserHandler* Extension::LoadFileBrowserHandler( |
| 2243 const DictionaryValue* file_browser_handler, string16* error) { |
| 2244 scoped_ptr<FileBrowserHandler> result( |
| 2245 new FileBrowserHandler()); |
| 2246 result->set_extension_id(id()); |
| 2247 |
| 2248 std::string id; |
| 2249 // Read the file action |id| (mandatory). |
| 2250 if (!file_browser_handler->HasKey(keys::kPageActionId) || |
| 2251 !file_browser_handler->GetString(keys::kPageActionId, &id)) { |
| 2252 *error = ASCIIToUTF16(errors::kInvalidPageActionId); |
| 2253 return NULL; |
| 2254 } |
| 2255 result->set_id(id); |
| 2256 |
| 2257 // Read the page action title from |default_title| (mandatory). |
| 2258 std::string title; |
| 2259 if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) || |
| 2260 !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) { |
| 2261 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); |
| 2262 return NULL; |
| 2263 } |
| 2264 result->set_title(title); |
| 2265 |
| 2266 // Initialize file filters (mandatory). |
| 2267 ListValue* list_value = NULL; |
| 2268 if (!file_browser_handler->HasKey(keys::kFileFilters) || |
| 2269 !file_browser_handler->GetList(keys::kFileFilters, &list_value) || |
| 2270 list_value->empty()) { |
| 2271 *error = ASCIIToUTF16(errors::kInvalidFileFiltersList); |
| 2272 return NULL; |
| 2273 } |
| 2274 for (size_t i = 0; i < list_value->GetSize(); ++i) { |
| 2275 std::string filter; |
| 2276 if (!list_value->GetString(i, &filter)) { |
| 2277 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2278 errors::kInvalidFileFilterValue, base::IntToString(i)); |
| 2279 return NULL; |
| 2280 } |
| 2281 StringToLowerASCII(&filter); |
| 2282 URLPattern pattern(URLPattern::SCHEME_FILESYSTEM); |
| 2283 if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) { |
| 2284 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2285 errors::kInvalidURLPatternError, filter); |
| 2286 return NULL; |
| 2287 } |
| 2288 std::string path = pattern.path(); |
| 2289 bool allowed = path == "*" || path == "*.*" || |
| 2290 (path.compare(0, 2, "*.") == 0 && |
| 2291 path.find_first_of('*', 2) == std::string::npos); |
| 2292 if (!allowed) { |
| 2293 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2294 errors::kInvalidURLPatternError, filter); |
| 2295 return NULL; |
| 2296 } |
| 2297 result->AddPattern(pattern); |
| 2298 } |
| 2299 |
| 2300 std::string default_icon; |
| 2301 // Read the file browser action |default_icon| (optional). |
| 2302 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { |
| 2303 if (!file_browser_handler->GetString( |
| 2304 keys::kPageActionDefaultIcon, &default_icon) || |
| 2305 default_icon.empty()) { |
| 2306 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); |
| 2307 return NULL; |
| 2308 } |
| 2309 result->set_icon_path(default_icon); |
| 2310 } |
| 2311 |
| 2312 return result.release(); |
| 2313 } |
| 2314 |
| 2315 bool Extension::LoadChromeURLOverrides(string16* error) { |
| 2316 if (!manifest_->HasKey(keys::kChromeURLOverrides)) |
| 2317 return true; |
| 2318 DictionaryValue* overrides = NULL; |
| 2319 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) { |
| 2320 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); |
| 2321 return false; |
| 2322 } |
| 2323 |
| 2324 // Validate that the overrides are all strings |
| 2325 for (DictionaryValue::key_iterator iter = overrides->begin_keys(); |
| 2326 iter != overrides->end_keys(); ++iter) { |
| 2327 std::string page = *iter; |
| 2328 std::string val; |
| 2329 // Restrict override pages to a list of supported URLs. |
| 2330 if ((page != chrome::kChromeUINewTabHost && |
| 2331 #if defined(USE_VIRTUAL_KEYBOARD) |
| 2332 page != chrome::kChromeUIKeyboardHost && |
| 2333 #endif |
| 2334 #if defined(OS_CHROMEOS) |
| 2335 page != chrome::kChromeUIActivationMessageHost && |
| 2336 #endif |
| 2337 page != chrome::kChromeUIBookmarksHost && |
| 2338 page != chrome::kChromeUIHistoryHost |
| 2339 #if defined(FILE_MANAGER_EXTENSION) |
| 2340 && |
| 2341 !(location() == COMPONENT && |
| 2342 page == chrome::kChromeUIFileManagerHost) |
| 2343 #endif |
| 2344 ) || |
| 2345 !overrides->GetStringWithoutPathExpansion(*iter, &val)) { |
| 2346 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); |
| 2347 return false; |
| 2348 } |
| 2349 // Replace the entry with a fully qualified chrome-extension:// URL. |
| 2350 chrome_url_overrides_[page] = GetResourceURL(val); |
| 2351 } |
| 2352 |
| 2353 // An extension may override at most one page. |
| 2354 if (overrides->size() > 1) { |
| 2355 *error = ASCIIToUTF16(errors::kMultipleOverrides); |
| 2356 return false; |
| 2357 } |
| 2358 |
| 2359 return true; |
| 2360 } |
| 2361 |
| 2362 bool Extension::LoadOmnibox(string16* error) { |
| 2363 if (!manifest_->HasKey(keys::kOmnibox)) |
| 2364 return true; |
| 2365 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || |
| 2366 omnibox_keyword_.empty()) { |
| 2367 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword); |
| 2368 return false; |
| 2369 } |
| 2370 return true; |
| 2371 } |
| 2372 |
| 2373 bool Extension::LoadTextToSpeechVoices(string16* error) { |
| 2374 if (!manifest_->HasKey(keys::kTtsEngine)) |
| 2375 return true; |
| 2376 DictionaryValue* tts_dict = NULL; |
| 2377 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) { |
| 2378 *error = ASCIIToUTF16(errors::kInvalidTts); |
| 2379 return false; |
| 2380 } |
| 2381 |
| 2382 if (tts_dict->HasKey(keys::kTtsVoices)) { |
| 2383 ListValue* tts_voices = NULL; |
| 2384 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) { |
| 2385 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); |
| 2386 return false; |
| 2387 } |
| 2388 |
| 2389 for (size_t i = 0; i < tts_voices->GetSize(); i++) { |
| 2390 DictionaryValue* one_tts_voice = NULL; |
| 2391 if (!tts_voices->GetDictionary(i, &one_tts_voice)) { |
| 2392 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); |
| 2393 return false; |
| 2394 } |
| 2395 |
| 2396 TtsVoice voice_data; |
| 2397 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) { |
| 2398 if (!one_tts_voice->GetString( |
| 2399 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) { |
| 2400 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName); |
| 2401 return false; |
| 2402 } |
| 2403 } |
| 2404 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) { |
| 2405 if (!one_tts_voice->GetString( |
| 2406 keys::kTtsVoicesLang, &voice_data.lang) || |
| 2407 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) { |
| 2408 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang); |
| 2409 return false; |
| 2410 } |
| 2411 } |
| 2412 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) { |
| 2413 if (!one_tts_voice->GetString( |
| 2414 keys::kTtsVoicesGender, &voice_data.gender) || |
| 2415 (voice_data.gender != keys::kTtsGenderMale && |
| 2416 voice_data.gender != keys::kTtsGenderFemale)) { |
| 2417 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender); |
| 2418 return false; |
| 2419 } |
| 2420 } |
| 2421 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) { |
| 2422 ListValue* event_types_list; |
| 2423 if (!one_tts_voice->GetList( |
| 2424 keys::kTtsVoicesEventTypes, &event_types_list)) { |
| 2425 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); |
| 2426 return false; |
| 2427 } |
| 2428 for (size_t i = 0; i < event_types_list->GetSize(); i++) { |
| 2429 std::string event_type; |
| 2430 if (!event_types_list->GetString(i, &event_type)) { |
| 2431 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); |
| 2432 return false; |
| 2433 } |
| 2434 if (event_type != keys::kTtsVoicesEventTypeEnd && |
| 2435 event_type != keys::kTtsVoicesEventTypeError && |
| 2436 event_type != keys::kTtsVoicesEventTypeMarker && |
| 2437 event_type != keys::kTtsVoicesEventTypeSentence && |
| 2438 event_type != keys::kTtsVoicesEventTypeStart && |
| 2439 event_type != keys::kTtsVoicesEventTypeWord) { |
| 2440 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); |
| 2441 return false; |
| 2442 } |
| 2443 if (voice_data.event_types.find(event_type) != |
| 2444 voice_data.event_types.end()) { |
| 2445 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); |
| 2446 return false; |
| 2447 } |
| 2448 voice_data.event_types.insert(event_type); |
| 2449 } |
| 2450 } |
| 2451 |
| 2452 tts_voices_.push_back(voice_data); |
| 2453 } |
| 2454 } |
| 2455 return true; |
| 2456 } |
| 2457 |
| 2458 bool Extension::LoadIncognitoMode(string16* error) { |
| 2459 // Apps default to split mode, extensions default to spanning. |
| 2460 incognito_split_mode_ = is_app(); |
| 2461 if (!manifest_->HasKey(keys::kIncognito)) |
| 2462 return true; |
| 2463 std::string value; |
| 2464 if (!manifest_->GetString(keys::kIncognito, &value)) { |
| 2465 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); |
| 2466 return false; |
| 2467 } |
| 2468 if (value == values::kIncognitoSpanning) { |
| 2469 incognito_split_mode_ = false; |
| 2470 } else if (value == values::kIncognitoSplit) { |
| 2471 incognito_split_mode_ = true; |
| 2472 } else { |
| 2473 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); |
| 2474 return false; |
| 2475 } |
| 2476 return true; |
| 2477 } |
| 2478 |
| 2479 bool Extension::LoadContentSecurityPolicy(string16* error) { |
| 2480 if (manifest_->HasKey(keys::kContentSecurityPolicy)) { |
| 2481 std::string content_security_policy; |
| 2482 if (!manifest_->GetString(keys::kContentSecurityPolicy, |
| 2483 &content_security_policy)) { |
| 2484 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); |
| 2485 return false; |
| 2486 } |
| 2487 if (!ContentSecurityPolicyIsLegal(content_security_policy)) { |
| 2488 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); |
| 2489 return false; |
| 2490 } |
| 2491 if (manifest_version_ >= 2 && |
| 2492 !ContentSecurityPolicyIsSecure(content_security_policy)) { |
| 2493 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); |
| 2494 return false; |
| 2495 } |
| 2496 |
| 2497 content_security_policy_ = content_security_policy; |
| 2498 } else if (manifest_version_ >= 2) { |
| 2499 // Manifest version 2 introduced a default Content-Security-Policy. |
| 2500 // TODO(abarth): Should we continue to let extensions override the |
| 2501 // default Content-Security-Policy? |
| 2502 content_security_policy_ = kDefaultContentSecurityPolicy; |
| 2503 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_)); |
| 2504 } |
| 2505 return true; |
| 2506 } |
| 2507 |
| 2508 bool Extension::LoadAppIsolation(string16* error) { |
| 2509 Value* temp = NULL; |
| 2510 if (!manifest_->Get(keys::kIsolation, &temp)) |
| 2511 return true; |
| 2512 |
| 2513 if (temp->GetType() != Value::TYPE_LIST) { |
| 2514 *error = ASCIIToUTF16(errors::kInvalidIsolation); |
| 2515 return false; |
| 2516 } |
| 2517 |
| 2518 ListValue* isolation_list = static_cast<ListValue*>(temp); |
| 2519 for (size_t i = 0; i < isolation_list->GetSize(); ++i) { |
| 2520 std::string isolation_string; |
| 2521 if (!isolation_list->GetString(i, &isolation_string)) { |
| 2522 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2523 errors::kInvalidIsolationValue, |
| 2524 base::UintToString(i)); |
| 2525 return false; |
| 2526 } |
| 2527 |
| 2528 // Check for isolated storage. |
| 2529 if (isolation_string == values::kIsolatedStorage) { |
| 2530 is_storage_isolated_ = true; |
| 2531 } else { |
| 2532 DLOG(WARNING) << "Did not recognize isolation type: " |
| 2533 << isolation_string; |
| 2534 } |
| 2535 } |
| 2536 return true; |
| 2537 } |
| 2538 |
| 2539 bool Extension::LoadThemeFeatures(string16* error) { |
| 2540 if (!manifest_->HasKey(keys::kTheme)) |
| 2541 return true; |
| 2542 DictionaryValue* theme_value = NULL; |
| 2543 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { |
| 2544 *error = ASCIIToUTF16(errors::kInvalidTheme); |
| 2545 return false; |
| 2546 } |
| 2547 if (!LoadThemeImages(theme_value, error)) |
| 2548 return false; |
| 2549 if (!LoadThemeColors(theme_value, error)) |
| 2550 return false; |
| 2551 if (!LoadThemeTints(theme_value, error)) |
| 2552 return false; |
| 2553 if (!LoadThemeDisplayProperties(theme_value, error)) |
| 2554 return false; |
| 2555 |
| 2556 return true; |
| 2557 } |
| 2558 |
| 2559 bool Extension::LoadThemeImages(const DictionaryValue* theme_value, |
| 2560 string16* error) { |
| 2561 DictionaryValue* images_value = NULL; |
| 2562 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { |
| 2563 // Validate that the images are all strings |
| 2564 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); |
| 2565 iter != images_value->end_keys(); ++iter) { |
| 2566 std::string val; |
| 2567 if (!images_value->GetString(*iter, &val)) { |
| 2568 *error = ASCIIToUTF16(errors::kInvalidThemeImages); |
| 2569 return false; |
| 2570 } |
| 2571 } |
| 2572 theme_images_.reset(images_value->DeepCopy()); |
| 2573 } |
| 2574 return true; |
| 2575 } |
| 2576 |
| 2577 bool Extension::LoadThemeColors(const DictionaryValue* theme_value, |
| 2578 string16* error) { |
| 2579 DictionaryValue* colors_value = NULL; |
| 2580 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { |
| 2581 // Validate that the colors are RGB or RGBA lists |
| 2582 for (DictionaryValue::key_iterator iter = colors_value->begin_keys(); |
| 2583 iter != colors_value->end_keys(); ++iter) { |
| 2584 ListValue* color_list = NULL; |
| 2585 double alpha = 0.0; |
| 2586 int color = 0; |
| 2587 // The color must be a list |
| 2588 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) || |
| 2589 // And either 3 items (RGB) or 4 (RGBA) |
| 2590 ((color_list->GetSize() != 3) && |
| 2591 ((color_list->GetSize() != 4) || |
| 2592 // For RGBA, the fourth item must be a real or int alpha value. |
| 2593 // Note that GetDouble() can get an integer value. |
| 2594 !color_list->GetDouble(3, &alpha))) || |
| 2595 // For both RGB and RGBA, the first three items must be ints (R,G,B) |
| 2596 !color_list->GetInteger(0, &color) || |
| 2597 !color_list->GetInteger(1, &color) || |
| 2598 !color_list->GetInteger(2, &color)) { |
| 2599 *error = ASCIIToUTF16(errors::kInvalidThemeColors); |
| 2600 return false; |
| 2601 } |
| 2602 } |
| 2603 theme_colors_.reset(colors_value->DeepCopy()); |
| 2604 } |
| 2605 return true; |
| 2606 } |
| 2607 |
| 2608 bool Extension::LoadThemeTints(const DictionaryValue* theme_value, |
| 2609 string16* error) { |
| 2610 DictionaryValue* tints_value = NULL; |
| 2611 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) { |
| 2612 // Validate that the tints are all reals. |
| 2613 for (DictionaryValue::key_iterator iter = tints_value->begin_keys(); |
| 2614 iter != tints_value->end_keys(); ++iter) { |
| 2615 ListValue* tint_list = NULL; |
| 2616 double v = 0.0; |
| 2617 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) || |
| 2618 tint_list->GetSize() != 3 || |
| 2619 !tint_list->GetDouble(0, &v) || |
| 2620 !tint_list->GetDouble(1, &v) || |
| 2621 !tint_list->GetDouble(2, &v)) { |
| 2622 *error = ASCIIToUTF16(errors::kInvalidThemeTints); |
| 2623 return false; |
| 2624 } |
| 2625 } |
| 2626 theme_tints_.reset(tints_value->DeepCopy()); |
| 2627 } |
| 2628 return true; |
| 2629 } |
| 2630 |
| 2631 bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value, |
| 2632 string16* error) { |
| 2633 DictionaryValue* display_properties_value = NULL; |
| 2634 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, |
| 2635 &display_properties_value)) { |
| 2636 theme_display_properties_.reset( |
| 2637 display_properties_value->DeepCopy()); |
| 2638 } |
| 2639 return true; |
| 2640 } |
| 2641 |
| 1581 // static | 2642 // static |
| 1582 bool Extension::IsTrustedId(const std::string& id) { | 2643 bool Extension::IsTrustedId(const std::string& id) { |
| 1583 // See http://b/4946060 for more details. | 2644 // See http://b/4946060 for more details. |
| 1584 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); | 2645 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); |
| 1585 } | 2646 } |
| 1586 | 2647 |
| 1587 Extension::Extension(const FilePath& path, | 2648 Extension::Extension(const FilePath& path, |
| 1588 scoped_ptr<extensions::Manifest> manifest) | 2649 scoped_ptr<extensions::Manifest> manifest) |
| 1589 : manifest_version_(0), | 2650 : manifest_version_(0), |
| 1590 incognito_split_mode_(false), | 2651 incognito_split_mode_(false), |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1754 const SkBitmap& Extension::GetDefaultIcon(bool is_app) { | 2815 const SkBitmap& Extension::GetDefaultIcon(bool is_app) { |
| 1755 if (is_app) { | 2816 if (is_app) { |
| 1756 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | 2817 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 1757 IDR_APP_DEFAULT_ICON); | 2818 IDR_APP_DEFAULT_ICON); |
| 1758 } else { | 2819 } else { |
| 1759 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | 2820 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 1760 IDR_EXTENSION_DEFAULT_ICON); | 2821 IDR_EXTENSION_DEFAULT_ICON); |
| 1761 } | 2822 } |
| 1762 } | 2823 } |
| 1763 | 2824 |
| 2825 // static |
| 1764 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { | 2826 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { |
| 1765 return GURL(std::string(chrome::kExtensionScheme) + | 2827 return GURL(std::string(chrome::kExtensionScheme) + |
| 1766 chrome::kStandardSchemeSeparator + extension_id + "/"); | 2828 chrome::kStandardSchemeSeparator + extension_id + "/"); |
| 1767 } | 2829 } |
| 1768 | 2830 |
| 1769 bool Extension::LoadManifestVersion(string16* error) { | |
| 1770 // Get the original value out of the dictionary so that we can validate it | |
| 1771 // more strictly. | |
| 1772 if (manifest_->value()->HasKey(keys::kManifestVersion)) { | |
| 1773 int manifest_version = 1; | |
| 1774 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) || | |
| 1775 manifest_version < 1) { | |
| 1776 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1777 return false; | |
| 1778 } | |
| 1779 } | |
| 1780 | |
| 1781 manifest_version_ = manifest_->GetManifestVersion(); | |
| 1782 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION && | |
| 1783 manifest_version_ < kModernManifestVersion && | |
| 1784 !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1785 switches::kAllowLegacyExtensionManifests)) { | |
| 1786 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1787 return false; | |
| 1788 } | |
| 1789 | |
| 1790 return true; | |
| 1791 } | |
| 1792 | |
| 1793 // static | |
| 1794 bool Extension::InitExtensionID(extensions::Manifest* manifest, | |
| 1795 const FilePath& path, | |
| 1796 const std::string& explicit_id, | |
| 1797 int creation_flags, | |
| 1798 string16* error) { | |
| 1799 if (!explicit_id.empty()) { | |
| 1800 manifest->set_extension_id(explicit_id); | |
| 1801 return true; | |
| 1802 } | |
| 1803 | |
| 1804 if (manifest->HasKey(keys::kPublicKey)) { | |
| 1805 std::string public_key; | |
| 1806 std::string public_key_bytes; | |
| 1807 std::string extension_id; | |
| 1808 if (!manifest->GetString(keys::kPublicKey, &public_key) || | |
| 1809 !ParsePEMKeyBytes(public_key, &public_key_bytes) || | |
| 1810 !GenerateId(public_key_bytes, &extension_id)) { | |
| 1811 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 1812 return false; | |
| 1813 } | |
| 1814 manifest->set_extension_id(extension_id); | |
| 1815 return true; | |
| 1816 } | |
| 1817 | |
| 1818 if (creation_flags & REQUIRE_KEY) { | |
| 1819 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 1820 return false; | |
| 1821 } else { | |
| 1822 // If there is a path, we generate the ID from it. This is useful for | |
| 1823 // development mode, because it keeps the ID stable across restarts and | |
| 1824 // reloading the extension. | |
| 1825 std::string extension_id = GenerateIdForPath(path); | |
| 1826 if (extension_id.empty()) { | |
| 1827 NOTREACHED() << "Could not create ID from path."; | |
| 1828 return false; | |
| 1829 } | |
| 1830 manifest->set_extension_id(extension_id); | |
| 1831 return true; | |
| 1832 } | |
| 1833 } | |
| 1834 | |
| 1835 bool Extension::InitFromValue(int flags, string16* error) { | 2831 bool Extension::InitFromValue(int flags, string16* error) { |
| 1836 DCHECK(error); | 2832 DCHECK(error); |
| 1837 | 2833 |
| 1838 base::AutoLock auto_lock(runtime_data_lock_); | 2834 base::AutoLock auto_lock(runtime_data_lock_); |
| 1839 | 2835 |
| 1840 // Initialize permissions with an empty, default permission set. | 2836 // Initialize permissions with an empty, default permission set. |
| 1841 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); | 2837 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); |
| 1842 optional_permission_set_ = new ExtensionPermissionSet(); | 2838 optional_permission_set_ = new ExtensionPermissionSet(); |
| 1843 required_permission_set_ = new ExtensionPermissionSet(); | 2839 required_permission_set_ = new ExtensionPermissionSet(); |
| 1844 | 2840 |
| 1845 creation_flags_ = flags; | 2841 creation_flags_ = flags; |
| 1846 | 2842 |
| 1847 if (!LoadManifestVersion(error)) | 2843 // Validate minimum Chrome version. We don't need to store this, since the |
| 2844 // extension is not valid if it is incorrect |
| 2845 if (!CheckMinimumChromeVersion(error)) |
| 2846 return false; |
| 2847 |
| 2848 if (!LoadRequiredFeatures(error)) |
| 1848 return false; | 2849 return false; |
| 1849 | 2850 |
| 1850 // We don't ned to validate because InitExtensionID already did that. | 2851 // We don't ned to validate because InitExtensionID already did that. |
| 1851 manifest_->GetString(keys::kPublicKey, &public_key_); | 2852 manifest_->GetString(keys::kPublicKey, &public_key_); |
| 1852 | 2853 |
| 1853 // Initialize the URL. | 2854 // Initialize permissions with an empty, default permission set. |
| 2855 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); |
| 2856 optional_permission_set_ = new ExtensionPermissionSet(); |
| 2857 required_permission_set_ = new ExtensionPermissionSet(); |
| 2858 |
| 1854 extension_url_ = Extension::GetBaseURLFromExtensionId(id()); | 2859 extension_url_ = Extension::GetBaseURLFromExtensionId(id()); |
| 1855 | 2860 |
| 1856 // Initialize version. | |
| 1857 std::string version_str; | |
| 1858 if (!manifest_->GetString(keys::kVersion, &version_str)) { | |
| 1859 *error = ASCIIToUTF16(errors::kInvalidVersion); | |
| 1860 return false; | |
| 1861 } | |
| 1862 version_.reset(Version::GetVersionFromString(version_str)); | |
| 1863 if (!version_.get() || | |
| 1864 version_->components().size() > 4) { | |
| 1865 *error = ASCIIToUTF16(errors::kInvalidVersion); | |
| 1866 return false; | |
| 1867 } | |
| 1868 | |
| 1869 // Initialize name. | |
| 1870 string16 localized_name; | |
| 1871 if (!manifest_->GetString(keys::kName, &localized_name)) { | |
| 1872 *error = ASCIIToUTF16(errors::kInvalidName); | |
| 1873 return false; | |
| 1874 } | |
| 1875 base::i18n::AdjustStringForLocaleDirection(&localized_name); | |
| 1876 name_ = UTF16ToUTF8(localized_name); | |
| 1877 | |
| 1878 // Load App settings. LoadExtent at least has to be done before | 2861 // Load App settings. LoadExtent at least has to be done before |
| 1879 // ParsePermissions(), because the valid permissions depend on what type of | 2862 // ParsePermissions(), because the valid permissions depend on what type of |
| 1880 // package this is. | 2863 // package this is. |
| 1881 if (is_app() && | 2864 if (is_app() && !LoadAppFeatures(error)) |
| 1882 (!LoadExtent(keys::kWebURLs, &extent_,errors::kInvalidWebURLs, | 2865 return false; |
| 1883 errors::kInvalidWebURL, error) || | 2866 |
| 1884 !LoadLaunchURL(error) || | |
| 1885 !LoadLaunchContainer(error))) { | |
| 1886 return false; | |
| 1887 } | |
| 1888 | |
| 1889 if (is_platform_app()) { | |
| 1890 if (launch_container() != extension_misc::LAUNCH_SHELL) { | |
| 1891 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform); | |
| 1892 return false; | |
| 1893 } | |
| 1894 } else if (launch_container() == extension_misc::LAUNCH_SHELL) { | |
| 1895 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform); | |
| 1896 return false; | |
| 1897 } | |
| 1898 | |
| 1899 // Initialize the permissions (optional). | |
| 1900 ExtensionAPIPermissionSet api_permissions; | 2867 ExtensionAPIPermissionSet api_permissions; |
| 1901 URLPatternSet host_permissions; | 2868 URLPatternSet host_permissions; |
| 1902 if (!ParsePermissions(keys::kPermissions, | 2869 if (!ParsePermissions(keys::kPermissions, |
| 1903 flags, | |
| 1904 error, | 2870 error, |
| 1905 &api_permissions, | 2871 &api_permissions, |
| 1906 &host_permissions)) { | 2872 &host_permissions)) { |
| 1907 return false; | 2873 return false; |
| 1908 } | 2874 } |
| 1909 | 2875 |
| 1910 // Initialize the optional permissions (optional). | |
| 1911 ExtensionAPIPermissionSet optional_api_permissions; | 2876 ExtensionAPIPermissionSet optional_api_permissions; |
| 1912 URLPatternSet optional_host_permissions; | 2877 URLPatternSet optional_host_permissions; |
| 1913 if (!ParsePermissions(keys::kOptionalPermissions, | 2878 if (!ParsePermissions(keys::kOptionalPermissions, |
| 1914 flags, | |
| 1915 error, | 2879 error, |
| 1916 &optional_api_permissions, | 2880 &optional_api_permissions, |
| 1917 &optional_host_permissions)) { | 2881 &optional_host_permissions)) { |
| 1918 return false; | 2882 return false; |
| 1919 } | 2883 } |
| 1920 | 2884 |
| 1921 // Initialize description (if present). | |
| 1922 if (manifest_->HasKey(keys::kDescription)) { | |
| 1923 if (!manifest_->GetString(keys::kDescription, &description_)) { | |
| 1924 *error = ASCIIToUTF16(errors::kInvalidDescription); | |
| 1925 return false; | |
| 1926 } | |
| 1927 } | |
| 1928 | |
| 1929 // Initialize homepage url (if present). | |
| 1930 if (manifest_->HasKey(keys::kHomepageURL)) { | |
| 1931 std::string tmp; | |
| 1932 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) { | |
| 1933 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1934 errors::kInvalidHomepageURL, ""); | |
| 1935 return false; | |
| 1936 } | |
| 1937 homepage_url_ = GURL(tmp); | |
| 1938 if (!homepage_url_.is_valid() || | |
| 1939 (!homepage_url_.SchemeIs("http") && | |
| 1940 !homepage_url_.SchemeIs("https"))) { | |
| 1941 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1942 errors::kInvalidHomepageURL, tmp); | |
| 1943 return false; | |
| 1944 } | |
| 1945 } | |
| 1946 | |
| 1947 // Initialize update url (if present). | |
| 1948 if (manifest_->HasKey(keys::kUpdateURL)) { | |
| 1949 std::string tmp; | |
| 1950 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) { | |
| 1951 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1952 errors::kInvalidUpdateURL, ""); | |
| 1953 return false; | |
| 1954 } | |
| 1955 update_url_ = GURL(tmp); | |
| 1956 if (!update_url_.is_valid() || | |
| 1957 update_url_.has_ref()) { | |
| 1958 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1959 errors::kInvalidUpdateURL, tmp); | |
| 1960 return false; | |
| 1961 } | |
| 1962 } | |
| 1963 | |
| 1964 // Validate minimum Chrome version (if present). We don't need to store this, | |
| 1965 // since the extension is not valid if it is incorrect. | |
| 1966 if (manifest_->HasKey(keys::kMinimumChromeVersion)) { | |
| 1967 std::string minimum_version_string; | |
| 1968 if (!manifest_->GetString(keys::kMinimumChromeVersion, | |
| 1969 &minimum_version_string)) { | |
| 1970 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); | |
| 1971 return false; | |
| 1972 } | |
| 1973 | |
| 1974 scoped_ptr<Version> minimum_version( | |
| 1975 Version::GetVersionFromString(minimum_version_string)); | |
| 1976 if (!minimum_version.get()) { | |
| 1977 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); | |
| 1978 return false; | |
| 1979 } | |
| 1980 | |
| 1981 chrome::VersionInfo current_version_info; | |
| 1982 if (!current_version_info.is_valid()) { | |
| 1983 NOTREACHED(); | |
| 1984 return false; | |
| 1985 } | |
| 1986 | |
| 1987 scoped_ptr<Version> current_version( | |
| 1988 Version::GetVersionFromString(current_version_info.Version())); | |
| 1989 if (!current_version.get()) { | |
| 1990 DCHECK(false); | |
| 1991 return false; | |
| 1992 } | |
| 1993 | |
| 1994 if (current_version->CompareTo(*minimum_version) < 0) { | |
| 1995 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1996 errors::kChromeVersionTooLow, | |
| 1997 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME), | |
| 1998 minimum_version_string); | |
| 1999 return false; | |
| 2000 } | |
| 2001 } | |
| 2002 | |
| 2003 // Initialize converted_from_user_script (if present) | |
| 2004 if (manifest_->HasKey(keys::kConvertedFromUserScript)) | |
| 2005 manifest_->GetBoolean(keys::kConvertedFromUserScript, | |
| 2006 &converted_from_user_script_); | |
| 2007 | |
| 2008 // Initialize commands (if present). | |
| 2009 if (manifest_->HasKey(keys::kCommands)) { | |
| 2010 DictionaryValue* commands = NULL; | |
| 2011 if (!manifest_->GetDictionary(keys::kCommands, &commands)) { | |
| 2012 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); | |
| 2013 return false; | |
| 2014 } | |
| 2015 | |
| 2016 int command_index = 0; | |
| 2017 for (DictionaryValue::key_iterator iter = commands->begin_keys(); | |
| 2018 iter != commands->end_keys(); ++iter) { | |
| 2019 ++command_index; | |
| 2020 | |
| 2021 DictionaryValue* command = NULL; | |
| 2022 if (!commands->GetDictionary(*iter, &command)) { | |
| 2023 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2024 errors::kInvalidKeyBindingDictionary, | |
| 2025 base::IntToString(command_index)); | |
| 2026 return false; | |
| 2027 } | |
| 2028 | |
| 2029 ExtensionKeybinding binding; | |
| 2030 if (!binding.Parse(command, *iter, command_index, error)) | |
| 2031 return false; // |error| already set. | |
| 2032 | |
| 2033 commands_.push_back(binding); | |
| 2034 } | |
| 2035 } | |
| 2036 | |
| 2037 // Initialize icons (if present). | |
| 2038 if (manifest_->HasKey(keys::kIcons)) { | |
| 2039 DictionaryValue* icons_value = NULL; | |
| 2040 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) { | |
| 2041 *error = ASCIIToUTF16(errors::kInvalidIcons); | |
| 2042 return false; | |
| 2043 } | |
| 2044 | |
| 2045 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) { | |
| 2046 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]); | |
| 2047 if (icons_value->HasKey(key)) { | |
| 2048 std::string icon_path; | |
| 2049 if (!icons_value->GetString(key, &icon_path)) { | |
| 2050 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2051 errors::kInvalidIconPath, key); | |
| 2052 return false; | |
| 2053 } | |
| 2054 | |
| 2055 if (!icon_path.empty() && icon_path[0] == '/') | |
| 2056 icon_path = icon_path.substr(1); | |
| 2057 | |
| 2058 if (icon_path.empty()) { | |
| 2059 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2060 errors::kInvalidIconPath, key); | |
| 2061 return false; | |
| 2062 } | |
| 2063 | |
| 2064 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path); | |
| 2065 } | |
| 2066 } | |
| 2067 } | |
| 2068 | |
| 2069 // Initialize themes (if present). | |
| 2070 if (manifest_->HasKey(keys::kTheme)) { | |
| 2071 DictionaryValue* theme_value = NULL; | |
| 2072 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { | |
| 2073 *error = ASCIIToUTF16(errors::kInvalidTheme); | |
| 2074 return false; | |
| 2075 } | |
| 2076 | |
| 2077 DictionaryValue* images_value = NULL; | |
| 2078 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { | |
| 2079 // Validate that the images are all strings | |
| 2080 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); | |
| 2081 iter != images_value->end_keys(); ++iter) { | |
| 2082 std::string val; | |
| 2083 if (!images_value->GetString(*iter, &val)) { | |
| 2084 *error = ASCIIToUTF16(errors::kInvalidThemeImages); | |
| 2085 return false; | |
| 2086 } | |
| 2087 } | |
| 2088 theme_images_.reset(images_value->DeepCopy()); | |
| 2089 } | |
| 2090 | |
| 2091 DictionaryValue* colors_value = NULL; | |
| 2092 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { | |
| 2093 // Validate that the colors are RGB or RGBA lists | |
| 2094 for (DictionaryValue::key_iterator iter = colors_value->begin_keys(); | |
| 2095 iter != colors_value->end_keys(); ++iter) { | |
| 2096 ListValue* color_list = NULL; | |
| 2097 double alpha = 0.0; | |
| 2098 int color = 0; | |
| 2099 // The color must be a list | |
| 2100 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) || | |
| 2101 // And either 3 items (RGB) or 4 (RGBA) | |
| 2102 ((color_list->GetSize() != 3) && | |
| 2103 ((color_list->GetSize() != 4) || | |
| 2104 // For RGBA, the fourth item must be a real or int alpha value. | |
| 2105 // Note that GetDouble() can get an integer value. | |
| 2106 !color_list->GetDouble(3, &alpha))) || | |
| 2107 // For both RGB and RGBA, the first three items must be ints (R,G,B) | |
| 2108 !color_list->GetInteger(0, &color) || | |
| 2109 !color_list->GetInteger(1, &color) || | |
| 2110 !color_list->GetInteger(2, &color)) { | |
| 2111 *error = ASCIIToUTF16(errors::kInvalidThemeColors); | |
| 2112 return false; | |
| 2113 } | |
| 2114 } | |
| 2115 theme_colors_.reset(colors_value->DeepCopy()); | |
| 2116 } | |
| 2117 | |
| 2118 DictionaryValue* tints_value = NULL; | |
| 2119 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) { | |
| 2120 // Validate that the tints are all reals. | |
| 2121 for (DictionaryValue::key_iterator iter = tints_value->begin_keys(); | |
| 2122 iter != tints_value->end_keys(); ++iter) { | |
| 2123 ListValue* tint_list = NULL; | |
| 2124 double v = 0.0; | |
| 2125 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) || | |
| 2126 tint_list->GetSize() != 3 || | |
| 2127 !tint_list->GetDouble(0, &v) || | |
| 2128 !tint_list->GetDouble(1, &v) || | |
| 2129 !tint_list->GetDouble(2, &v)) { | |
| 2130 *error = ASCIIToUTF16(errors::kInvalidThemeTints); | |
| 2131 return false; | |
| 2132 } | |
| 2133 } | |
| 2134 theme_tints_.reset(tints_value->DeepCopy()); | |
| 2135 } | |
| 2136 | |
| 2137 DictionaryValue* display_properties_value = NULL; | |
| 2138 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, | |
| 2139 &display_properties_value)) { | |
| 2140 theme_display_properties_.reset( | |
| 2141 display_properties_value->DeepCopy()); | |
| 2142 } | |
| 2143 | |
| 2144 return true; | |
| 2145 } | |
| 2146 | |
| 2147 // Initialize plugins (optional). | |
| 2148 if (manifest_->HasKey(keys::kPlugins)) { | |
| 2149 ListValue* list_value = NULL; | |
| 2150 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | |
| 2151 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 2152 return false; | |
| 2153 } | |
| 2154 | |
| 2155 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2156 DictionaryValue* plugin_value = NULL; | |
| 2157 std::string path_str; | |
| 2158 bool is_public = false; | |
| 2159 | |
| 2160 if (!list_value->GetDictionary(i, &plugin_value)) { | |
| 2161 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 2162 return false; | |
| 2163 } | |
| 2164 | |
| 2165 // Get plugins[i].path. | |
| 2166 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) { | |
| 2167 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2168 errors::kInvalidPluginsPath, base::IntToString(i)); | |
| 2169 return false; | |
| 2170 } | |
| 2171 | |
| 2172 // Get plugins[i].content (optional). | |
| 2173 if (plugin_value->HasKey(keys::kPluginsPublic)) { | |
| 2174 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) { | |
| 2175 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2176 errors::kInvalidPluginsPublic, base::IntToString(i)); | |
| 2177 return false; | |
| 2178 } | |
| 2179 } | |
| 2180 | |
| 2181 // We don't allow extension plugins to run on Chrome OS. We still | |
| 2182 // parse the manifest entry so that error messages are consistently | |
| 2183 // displayed across platforms. | |
| 2184 #if !defined(OS_CHROMEOS) | |
| 2185 plugins_.push_back(PluginInfo()); | |
| 2186 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str)); | |
| 2187 plugins_.back().is_public = is_public; | |
| 2188 #endif | |
| 2189 } | |
| 2190 } | |
| 2191 | |
| 2192 if (manifest_->HasKey(keys::kNaClModules)) { | |
| 2193 ListValue* list_value = NULL; | |
| 2194 if (!manifest_->GetList(keys::kNaClModules, &list_value)) { | |
| 2195 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 2196 return false; | |
| 2197 } | |
| 2198 | |
| 2199 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2200 DictionaryValue* module_value = NULL; | |
| 2201 std::string path_str; | |
| 2202 std::string mime_type; | |
| 2203 | |
| 2204 if (!list_value->GetDictionary(i, &module_value)) { | |
| 2205 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 2206 return false; | |
| 2207 } | |
| 2208 | |
| 2209 // Get nacl_modules[i].path. | |
| 2210 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) { | |
| 2211 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2212 errors::kInvalidNaClModulesPath, base::IntToString(i)); | |
| 2213 return false; | |
| 2214 } | |
| 2215 | |
| 2216 // Get nacl_modules[i].mime_type. | |
| 2217 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) { | |
| 2218 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2219 errors::kInvalidNaClModulesMIMEType, base::IntToString(i)); | |
| 2220 return false; | |
| 2221 } | |
| 2222 | |
| 2223 nacl_modules_.push_back(NaClModuleInfo()); | |
| 2224 nacl_modules_.back().url = GetResourceURL(path_str); | |
| 2225 nacl_modules_.back().mime_type = mime_type; | |
| 2226 } | |
| 2227 } | |
| 2228 | |
| 2229 // Initialize content scripts (optional). | |
| 2230 if (manifest_->HasKey(keys::kContentScripts)) { | |
| 2231 ListValue* list_value; | |
| 2232 if (!manifest_->GetList(keys::kContentScripts, &list_value)) { | |
| 2233 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList); | |
| 2234 return false; | |
| 2235 } | |
| 2236 | |
| 2237 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2238 DictionaryValue* content_script = NULL; | |
| 2239 if (!list_value->GetDictionary(i, &content_script)) { | |
| 2240 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2241 errors::kInvalidContentScript, base::IntToString(i)); | |
| 2242 return false; | |
| 2243 } | |
| 2244 | |
| 2245 UserScript script; | |
| 2246 if (!LoadUserScriptHelper(content_script, i, flags, error, &script)) | |
| 2247 return false; // Failed to parse script context definition. | |
| 2248 script.set_extension_id(id()); | |
| 2249 if (converted_from_user_script_) { | |
| 2250 script.set_emulate_greasemonkey(true); | |
| 2251 script.set_match_all_frames(true); // Greasemonkey matches all frames. | |
| 2252 } | |
| 2253 content_scripts_.push_back(script); | |
| 2254 } | |
| 2255 } | |
| 2256 | |
| 2257 // Initialize web accessible resources (optional). | |
| 2258 if (manifest_->HasKey(keys::kWebAccessibleResources)) { | |
| 2259 ListValue* list_value; | |
| 2260 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) { | |
| 2261 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList); | |
| 2262 return false; | |
| 2263 } | |
| 2264 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2265 std::string relative_path; | |
| 2266 if (!list_value->GetString(i, &relative_path)) { | |
| 2267 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2268 errors::kInvalidWebAccessibleResource, base::IntToString(i)); | |
| 2269 return false; | |
| 2270 } | |
| 2271 if (relative_path[0] != '/') | |
| 2272 relative_path = '/' + relative_path; | |
| 2273 web_accessible_resources_.insert(relative_path); | |
| 2274 } | |
| 2275 } | |
| 2276 | |
| 2277 // Initialize page action (optional). | |
| 2278 DictionaryValue* page_action_value = NULL; | |
| 2279 | |
| 2280 if (manifest_->HasKey(keys::kPageActions)) { | |
| 2281 ListValue* list_value = NULL; | |
| 2282 if (!manifest_->GetList(keys::kPageActions, &list_value)) { | |
| 2283 *error = ASCIIToUTF16(errors::kInvalidPageActionsList); | |
| 2284 return false; | |
| 2285 } | |
| 2286 | |
| 2287 size_t list_value_length = list_value->GetSize(); | |
| 2288 | |
| 2289 if (list_value_length == 0u) { | |
| 2290 // A list with zero items is allowed, and is equivalent to not having | |
| 2291 // a page_actions key in the manifest. Don't set |page_action_value|. | |
| 2292 } else if (list_value_length == 1u) { | |
| 2293 if (!list_value->GetDictionary(0, &page_action_value)) { | |
| 2294 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2295 return false; | |
| 2296 } | |
| 2297 } else { // list_value_length > 1u. | |
| 2298 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize); | |
| 2299 return false; | |
| 2300 } | |
| 2301 } else if (manifest_->HasKey(keys::kPageAction)) { | |
| 2302 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { | |
| 2303 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2304 return false; | |
| 2305 } | |
| 2306 } | |
| 2307 | |
| 2308 // If page_action_value is not NULL, then there was a valid page action. | |
| 2309 if (page_action_value) { | |
| 2310 page_action_.reset( | |
| 2311 LoadExtensionActionHelper(page_action_value, error)); | |
| 2312 if (!page_action_.get()) | |
| 2313 return false; // Failed to parse page action definition. | |
| 2314 } | |
| 2315 | |
| 2316 // Initialize browser action (optional). | |
| 2317 if (manifest_->HasKey(keys::kBrowserAction)) { | |
| 2318 DictionaryValue* browser_action_value = NULL; | |
| 2319 if (!manifest_->GetDictionary(keys::kBrowserAction, | |
| 2320 &browser_action_value)) { | |
| 2321 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); | |
| 2322 return false; | |
| 2323 } | |
| 2324 | |
| 2325 browser_action_.reset( | |
| 2326 LoadExtensionActionHelper(browser_action_value, error)); | |
| 2327 if (!browser_action_.get()) | |
| 2328 return false; // Failed to parse browser action definition. | |
| 2329 } | |
| 2330 | |
| 2331 // Initialize file browser actions (optional). | |
| 2332 if (manifest_->HasKey(keys::kFileBrowserHandlers)) { | |
| 2333 ListValue* file_browser_handlers_value = NULL; | |
| 2334 if (!manifest_->GetList(keys::kFileBrowserHandlers, | |
| 2335 &file_browser_handlers_value)) { | |
| 2336 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2337 return false; | |
| 2338 } | |
| 2339 | |
| 2340 file_browser_handlers_.reset( | |
| 2341 LoadFileBrowserHandlers(file_browser_handlers_value, error)); | |
| 2342 if (!file_browser_handlers_.get()) | |
| 2343 return false; // Failed to parse file browser actions definition. | |
| 2344 } | |
| 2345 | |
| 2346 // App isolation. | 2885 // App isolation. |
| 2347 if (api_permissions.count(ExtensionAPIPermission::kExperimental)) { | 2886 if (api_permissions.count(ExtensionAPIPermission::kExperimental) && |
| 2348 if (is_app() && !LoadAppIsolation(error)) | 2887 is_app() && !LoadAppIsolation(error)) |
| 2349 return false; | 2888 return false; |
| 2350 } | 2889 |
| 2351 | 2890 if (!LoadSharedFeatures(api_permissions, error)) |
| 2352 // Initialize options page url (optional). | 2891 return false; |
| 2353 if (manifest_->HasKey(keys::kOptionsPage)) { | 2892 |
| 2354 std::string options_str; | 2893 |
| 2355 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) { | 2894 if (!LoadExtensionFeatures(api_permissions, error)) |
| 2356 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | 2895 return false; |
| 2357 return false; | 2896 |
| 2358 } | 2897 if (!LoadThemeFeatures(error)) |
| 2359 | 2898 return false; |
| 2360 if (is_hosted_app()) { | |
| 2361 // hosted apps require an absolute URL. | |
| 2362 GURL options_url(options_str); | |
| 2363 if (!options_url.is_valid() || | |
| 2364 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) { | |
| 2365 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp); | |
| 2366 return false; | |
| 2367 } | |
| 2368 options_url_ = options_url; | |
| 2369 } else { | |
| 2370 GURL absolute(options_str); | |
| 2371 if (absolute.is_valid()) { | |
| 2372 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage); | |
| 2373 return false; | |
| 2374 } | |
| 2375 options_url_ = GetResourceURL(options_str); | |
| 2376 if (!options_url_.is_valid()) { | |
| 2377 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 2378 return false; | |
| 2379 } | |
| 2380 } | |
| 2381 } | |
| 2382 | |
| 2383 if (!LoadBackgroundScripts(error)) | |
| 2384 return false; | |
| 2385 | |
| 2386 if (!LoadBackgroundPage(api_permissions, error)) | |
| 2387 return false; | |
| 2388 | |
| 2389 if (!LoadBackgroundPersistent(api_permissions, error)) | |
| 2390 return false; | |
| 2391 | |
| 2392 if (!LoadBackgroundAllowJsAccess(api_permissions, error)) | |
| 2393 return false; | |
| 2394 | |
| 2395 if (manifest_->HasKey(keys::kDefaultLocale)) { | |
| 2396 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) || | |
| 2397 !l10n_util::IsValidLocaleSyntax(default_locale_)) { | |
| 2398 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale); | |
| 2399 return false; | |
| 2400 } | |
| 2401 } | |
| 2402 | |
| 2403 // Chrome URL overrides (optional) | |
| 2404 if (manifest_->HasKey(keys::kChromeURLOverrides)) { | |
| 2405 DictionaryValue* overrides = NULL; | |
| 2406 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) { | |
| 2407 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2408 return false; | |
| 2409 } | |
| 2410 | |
| 2411 // Validate that the overrides are all strings | |
| 2412 for (DictionaryValue::key_iterator iter = overrides->begin_keys(); | |
| 2413 iter != overrides->end_keys(); ++iter) { | |
| 2414 std::string page = *iter; | |
| 2415 std::string val; | |
| 2416 // Restrict override pages to a list of supported URLs. | |
| 2417 if ((page != chrome::kChromeUINewTabHost && | |
| 2418 #if defined(USE_VIRTUAL_KEYBOARD) | |
| 2419 page != chrome::kChromeUIKeyboardHost && | |
| 2420 #endif | |
| 2421 #if defined(OS_CHROMEOS) | |
| 2422 page != chrome::kChromeUIActivationMessageHost && | |
| 2423 #endif | |
| 2424 page != chrome::kChromeUIBookmarksHost && | |
| 2425 page != chrome::kChromeUIHistoryHost | |
| 2426 #if defined(FILE_MANAGER_EXTENSION) | |
| 2427 && | |
| 2428 !(location() == COMPONENT && | |
| 2429 page == chrome::kChromeUIFileManagerHost) | |
| 2430 #endif | |
| 2431 ) || | |
| 2432 !overrides->GetStringWithoutPathExpansion(*iter, &val)) { | |
| 2433 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2434 return false; | |
| 2435 } | |
| 2436 // Replace the entry with a fully qualified chrome-extension:// URL. | |
| 2437 chrome_url_overrides_[page] = GetResourceURL(val); | |
| 2438 } | |
| 2439 | |
| 2440 // An extension may override at most one page. | |
| 2441 if (overrides->size() > 1) { | |
| 2442 *error = ASCIIToUTF16(errors::kMultipleOverrides); | |
| 2443 return false; | |
| 2444 } | |
| 2445 } | |
| 2446 | |
| 2447 if (manifest_->HasKey(keys::kInputComponents)) { | |
| 2448 ListValue* list_value = NULL; | |
| 2449 if (!manifest_->GetList(keys::kInputComponents, &list_value)) { | |
| 2450 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 2451 return false; | |
| 2452 } | |
| 2453 | |
| 2454 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2455 DictionaryValue* module_value = NULL; | |
| 2456 std::string name_str; | |
| 2457 InputComponentType type; | |
| 2458 std::string id_str; | |
| 2459 std::string description_str; | |
| 2460 std::string language_str; | |
| 2461 std::set<std::string> layouts; | |
| 2462 std::string shortcut_keycode_str; | |
| 2463 bool shortcut_alt = false; | |
| 2464 bool shortcut_ctrl = false; | |
| 2465 bool shortcut_shift = false; | |
| 2466 | |
| 2467 if (!list_value->GetDictionary(i, &module_value)) { | |
| 2468 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 2469 return false; | |
| 2470 } | |
| 2471 | |
| 2472 // Get input_components[i].name. | |
| 2473 if (!module_value->GetString(keys::kName, &name_str)) { | |
| 2474 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2475 errors::kInvalidInputComponentName, base::IntToString(i)); | |
| 2476 return false; | |
| 2477 } | |
| 2478 | |
| 2479 // Get input_components[i].type. | |
| 2480 std::string type_str; | |
| 2481 if (module_value->GetString(keys::kType, &type_str)) { | |
| 2482 if (type_str == "ime") { | |
| 2483 type = INPUT_COMPONENT_TYPE_IME; | |
| 2484 } else if (type_str == "virtual_keyboard") { | |
| 2485 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { | |
| 2486 // Virtual Keyboards require the experimental flag. | |
| 2487 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2488 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2489 return false; | |
| 2490 } | |
| 2491 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD; | |
| 2492 } else { | |
| 2493 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2494 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2495 return false; | |
| 2496 } | |
| 2497 } else { | |
| 2498 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2499 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2500 return false; | |
| 2501 } | |
| 2502 | |
| 2503 // Get input_components[i].id. | |
| 2504 if (!module_value->GetString(keys::kId, &id_str)) { | |
| 2505 id_str = ""; | |
| 2506 } | |
| 2507 | |
| 2508 // Get input_components[i].description. | |
| 2509 if (!module_value->GetString(keys::kDescription, &description_str)) { | |
| 2510 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2511 errors::kInvalidInputComponentDescription, base::IntToString(i)); | |
| 2512 return false; | |
| 2513 } | |
| 2514 | |
| 2515 // Get input_components[i].language. | |
| 2516 if (!module_value->GetString(keys::kLanguage, &language_str)) { | |
| 2517 language_str = ""; | |
| 2518 } | |
| 2519 | |
| 2520 // Get input_components[i].layouts. | |
| 2521 ListValue* layouts_value = NULL; | |
| 2522 if (!module_value->GetList(keys::kLayouts, &layouts_value)) { | |
| 2523 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts); | |
| 2524 return false; | |
| 2525 } | |
| 2526 | |
| 2527 for (size_t j = 0; j < layouts_value->GetSize(); ++j) { | |
| 2528 std::string layout_name_str; | |
| 2529 if (!layouts_value->GetString(j, &layout_name_str)) { | |
| 2530 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2531 errors::kInvalidInputComponentLayoutName, base::IntToString(i), | |
| 2532 base::IntToString(j)); | |
| 2533 return false; | |
| 2534 } | |
| 2535 layouts.insert(layout_name_str); | |
| 2536 } | |
| 2537 | |
| 2538 if (module_value->HasKey(keys::kShortcutKey)) { | |
| 2539 DictionaryValue* shortcut_value = NULL; | |
| 2540 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) { | |
| 2541 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2542 errors::kInvalidInputComponentShortcutKey, base::IntToString(i)); | |
| 2543 return false; | |
| 2544 } | |
| 2545 | |
| 2546 // Get input_components[i].shortcut_keycode. | |
| 2547 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) { | |
| 2548 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2549 errors::kInvalidInputComponentShortcutKeycode, | |
| 2550 base::IntToString(i)); | |
| 2551 return false; | |
| 2552 } | |
| 2553 | |
| 2554 // Get input_components[i].shortcut_alt. | |
| 2555 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) { | |
| 2556 shortcut_alt = false; | |
| 2557 } | |
| 2558 | |
| 2559 // Get input_components[i].shortcut_ctrl. | |
| 2560 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) { | |
| 2561 shortcut_ctrl = false; | |
| 2562 } | |
| 2563 | |
| 2564 // Get input_components[i].shortcut_shift. | |
| 2565 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) { | |
| 2566 shortcut_shift = false; | |
| 2567 } | |
| 2568 } | |
| 2569 | |
| 2570 input_components_.push_back(InputComponentInfo()); | |
| 2571 input_components_.back().name = name_str; | |
| 2572 input_components_.back().type = type; | |
| 2573 input_components_.back().id = id_str; | |
| 2574 input_components_.back().description = description_str; | |
| 2575 input_components_.back().language = language_str; | |
| 2576 input_components_.back().layouts.insert(layouts.begin(), layouts.end()); | |
| 2577 input_components_.back().shortcut_keycode = shortcut_keycode_str; | |
| 2578 input_components_.back().shortcut_alt = shortcut_alt; | |
| 2579 input_components_.back().shortcut_ctrl = shortcut_ctrl; | |
| 2580 input_components_.back().shortcut_shift = shortcut_shift; | |
| 2581 } | |
| 2582 } | |
| 2583 | |
| 2584 if (manifest_->HasKey(keys::kOmnibox)) { | |
| 2585 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || | |
| 2586 omnibox_keyword_.empty()) { | |
| 2587 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword); | |
| 2588 return false; | |
| 2589 } | |
| 2590 } | |
| 2591 | |
| 2592 if (manifest_->HasKey(keys::kContentSecurityPolicy)) { | |
| 2593 std::string content_security_policy; | |
| 2594 if (!manifest_->GetString(keys::kContentSecurityPolicy, | |
| 2595 &content_security_policy)) { | |
| 2596 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2597 return false; | |
| 2598 } | |
| 2599 if (!ContentSecurityPolicyIsLegal(content_security_policy)) { | |
| 2600 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2601 return false; | |
| 2602 } | |
| 2603 if (manifest_version_ >= 2 && | |
| 2604 !ContentSecurityPolicyIsSecure(content_security_policy)) { | |
| 2605 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2606 return false; | |
| 2607 } | |
| 2608 | |
| 2609 content_security_policy_ = content_security_policy; | |
| 2610 } else if (manifest_version_ >= 2) { | |
| 2611 // Manifest version 2 introduced a default Content-Security-Policy. | |
| 2612 // TODO(abarth): Should we continue to let extensions override the | |
| 2613 // default Content-Security-Policy? | |
| 2614 content_security_policy_ = kDefaultContentSecurityPolicy; | |
| 2615 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_)); | |
| 2616 } | |
| 2617 | |
| 2618 // Initialize devtools page url (optional). | |
| 2619 if (manifest_->HasKey(keys::kDevToolsPage)) { | |
| 2620 std::string devtools_str; | |
| 2621 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) { | |
| 2622 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage); | |
| 2623 return false; | |
| 2624 } | |
| 2625 devtools_url_ = GetResourceURL(devtools_str); | |
| 2626 } | |
| 2627 | |
| 2628 // Initialize text-to-speech voices (optional). | |
| 2629 if (manifest_->HasKey(keys::kTtsEngine)) { | |
| 2630 DictionaryValue* tts_dict = NULL; | |
| 2631 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) { | |
| 2632 *error = ASCIIToUTF16(errors::kInvalidTts); | |
| 2633 return false; | |
| 2634 } | |
| 2635 | |
| 2636 if (tts_dict->HasKey(keys::kTtsVoices)) { | |
| 2637 ListValue* tts_voices = NULL; | |
| 2638 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) { | |
| 2639 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2640 return false; | |
| 2641 } | |
| 2642 | |
| 2643 for (size_t i = 0; i < tts_voices->GetSize(); i++) { | |
| 2644 DictionaryValue* one_tts_voice = NULL; | |
| 2645 if (!tts_voices->GetDictionary(i, &one_tts_voice)) { | |
| 2646 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2647 return false; | |
| 2648 } | |
| 2649 | |
| 2650 TtsVoice voice_data; | |
| 2651 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) { | |
| 2652 if (!one_tts_voice->GetString( | |
| 2653 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) { | |
| 2654 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName); | |
| 2655 return false; | |
| 2656 } | |
| 2657 } | |
| 2658 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) { | |
| 2659 if (!one_tts_voice->GetString( | |
| 2660 keys::kTtsVoicesLang, &voice_data.lang) || | |
| 2661 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) { | |
| 2662 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang); | |
| 2663 return false; | |
| 2664 } | |
| 2665 } | |
| 2666 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) { | |
| 2667 if (!one_tts_voice->GetString( | |
| 2668 keys::kTtsVoicesGender, &voice_data.gender) || | |
| 2669 (voice_data.gender != keys::kTtsGenderMale && | |
| 2670 voice_data.gender != keys::kTtsGenderFemale)) { | |
| 2671 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender); | |
| 2672 return false; | |
| 2673 } | |
| 2674 } | |
| 2675 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) { | |
| 2676 ListValue* event_types_list; | |
| 2677 if (!one_tts_voice->GetList( | |
| 2678 keys::kTtsVoicesEventTypes, &event_types_list)) { | |
| 2679 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2680 return false; | |
| 2681 } | |
| 2682 for (size_t i = 0; i < event_types_list->GetSize(); i++) { | |
| 2683 std::string event_type; | |
| 2684 if (!event_types_list->GetString(i, &event_type)) { | |
| 2685 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2686 return false; | |
| 2687 } | |
| 2688 if (event_type != keys::kTtsVoicesEventTypeEnd && | |
| 2689 event_type != keys::kTtsVoicesEventTypeError && | |
| 2690 event_type != keys::kTtsVoicesEventTypeMarker && | |
| 2691 event_type != keys::kTtsVoicesEventTypeSentence && | |
| 2692 event_type != keys::kTtsVoicesEventTypeStart && | |
| 2693 event_type != keys::kTtsVoicesEventTypeWord) { | |
| 2694 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2695 return false; | |
| 2696 } | |
| 2697 if (voice_data.event_types.find(event_type) != | |
| 2698 voice_data.event_types.end()) { | |
| 2699 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2700 return false; | |
| 2701 } | |
| 2702 voice_data.event_types.insert(event_type); | |
| 2703 } | |
| 2704 } | |
| 2705 | |
| 2706 tts_voices_.push_back(voice_data); | |
| 2707 } | |
| 2708 } | |
| 2709 } | |
| 2710 | |
| 2711 // Initialize web intents (optional). | |
| 2712 if (!LoadWebIntentServices(error)) | |
| 2713 return false; | |
| 2714 | |
| 2715 // Initialize incognito behavior. Apps default to split mode, extensions | |
| 2716 // default to spanning. | |
| 2717 incognito_split_mode_ = is_app(); | |
| 2718 if (manifest_->HasKey(keys::kIncognito)) { | |
| 2719 std::string value; | |
| 2720 if (!manifest_->GetString(keys::kIncognito, &value)) { | |
| 2721 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2722 return false; | |
| 2723 } | |
| 2724 if (value == values::kIncognitoSpanning) { | |
| 2725 incognito_split_mode_ = false; | |
| 2726 } else if (value == values::kIncognitoSplit) { | |
| 2727 incognito_split_mode_ = true; | |
| 2728 } else { | |
| 2729 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2730 return false; | |
| 2731 } | |
| 2732 } | |
| 2733 | |
| 2734 // Initialize offline-enabled status. Defaults to false. | |
| 2735 if (manifest_->HasKey(keys::kOfflineEnabled)) { | |
| 2736 if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { | |
| 2737 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled); | |
| 2738 return false; | |
| 2739 } | |
| 2740 } | |
| 2741 | |
| 2742 // Initialize requirements (optional). Not actually persisted (they're only | |
| 2743 // used by the store), but still validated. | |
| 2744 if (manifest_->HasKey(keys::kRequirements)) { | |
| 2745 DictionaryValue* requirements_value = NULL; | |
| 2746 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) { | |
| 2747 *error = ASCIIToUTF16(errors::kInvalidRequirements); | |
| 2748 return false; | |
| 2749 } | |
| 2750 | |
| 2751 for (DictionaryValue::key_iterator it = requirements_value->begin_keys(); | |
| 2752 it != requirements_value->end_keys(); ++it) { | |
| 2753 DictionaryValue* requirement_value; | |
| 2754 if (!requirements_value->GetDictionaryWithoutPathExpansion( | |
| 2755 *it, &requirement_value)) { | |
| 2756 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2757 errors::kInvalidRequirement, *it); | |
| 2758 return false; | |
| 2759 } | |
| 2760 } | |
| 2761 } | |
| 2762 | 2899 |
| 2763 if (HasMultipleUISurfaces()) { | 2900 if (HasMultipleUISurfaces()) { |
| 2764 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); | 2901 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); |
| 2765 return false; | 2902 return false; |
| 2766 } | 2903 } |
| 2767 | 2904 |
| 2768 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( | 2905 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( |
| 2769 this, api_permissions, host_permissions)); | 2906 this, api_permissions, host_permissions)); |
| 2770 required_permission_set_ = new ExtensionPermissionSet( | 2907 required_permission_set_ = new ExtensionPermissionSet( |
| 2771 this, api_permissions, host_permissions); | 2908 this, api_permissions, host_permissions); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2921 GURL Extension::GetIconURL(int size, | 3058 GURL Extension::GetIconURL(int size, |
| 2922 ExtensionIconSet::MatchType match_type) const { | 3059 ExtensionIconSet::MatchType match_type) const { |
| 2923 std::string path = icons().Get(size, match_type); | 3060 std::string path = icons().Get(size, match_type); |
| 2924 if (path.empty()) | 3061 if (path.empty()) |
| 2925 return GURL(); | 3062 return GURL(); |
| 2926 else | 3063 else |
| 2927 return GetResourceURL(path); | 3064 return GetResourceURL(path); |
| 2928 } | 3065 } |
| 2929 | 3066 |
| 2930 bool Extension::ParsePermissions(const char* key, | 3067 bool Extension::ParsePermissions(const char* key, |
| 2931 int flags, | |
| 2932 string16* error, | 3068 string16* error, |
| 2933 ExtensionAPIPermissionSet* api_permissions, | 3069 ExtensionAPIPermissionSet* api_permissions, |
| 2934 URLPatternSet* host_permissions) { | 3070 URLPatternSet* host_permissions) { |
| 2935 if (manifest_->HasKey(key)) { | 3071 if (manifest_->HasKey(key)) { |
| 2936 ListValue* permissions = NULL; | 3072 ListValue* permissions = NULL; |
| 2937 if (!manifest_->GetList(key, &permissions)) { | 3073 if (!manifest_->GetList(key, &permissions)) { |
| 2938 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 3074 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2939 errors::kInvalidPermissions, ""); | 3075 errors::kInvalidPermissions, ""); |
| 2940 return false; | 3076 return false; |
| 2941 } | 3077 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2972 return false; | 3108 return false; |
| 2973 } | 3109 } |
| 2974 | 3110 |
| 2975 // The path component is not used for host permissions, so we force it | 3111 // The path component is not used for host permissions, so we force it |
| 2976 // to match all paths. | 3112 // to match all paths. |
| 2977 pattern.SetPath("/*"); | 3113 pattern.SetPath("/*"); |
| 2978 | 3114 |
| 2979 if (pattern.MatchesScheme(chrome::kFileScheme) && | 3115 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 2980 !CanExecuteScriptEverywhere()) { | 3116 !CanExecuteScriptEverywhere()) { |
| 2981 wants_file_access_ = true; | 3117 wants_file_access_ = true; |
| 2982 if (!(flags & ALLOW_FILE_ACCESS)) | 3118 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) |
| 2983 pattern.SetValidSchemes( | 3119 pattern.SetValidSchemes( |
| 2984 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 3120 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 2985 } | 3121 } |
| 2986 | 3122 |
| 2987 host_permissions->AddPattern(pattern); | 3123 host_permissions->AddPattern(pattern); |
| 2988 } | 3124 } |
| 2989 | 3125 |
| 2990 // If it's not a host permission, then it's probably an unknown API | 3126 // If it's not a host permission, then it's probably an unknown API |
| 2991 // permission. Do not throw an error so extensions can retain | 3127 // permission. Do not throw an error so extensions can retain |
| 2992 // backwards compatability (http://crbug.com/42742). | 3128 // backwards compatability (http://crbug.com/42742). |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3161 // extension with options. All other menu items like uninstall have | 3297 // extension with options. All other menu items like uninstall have |
| 3162 // no sense for component extensions. | 3298 // no sense for component extensions. |
| 3163 return location() != Extension::COMPONENT; | 3299 return location() != Extension::COMPONENT; |
| 3164 } | 3300 } |
| 3165 | 3301 |
| 3166 bool Extension::CanSpecifyAPIPermission( | 3302 bool Extension::CanSpecifyAPIPermission( |
| 3167 const ExtensionAPIPermission* permission, | 3303 const ExtensionAPIPermission* permission, |
| 3168 string16* error) const { | 3304 string16* error) const { |
| 3169 if (location() == Extension::COMPONENT) | 3305 if (location() == Extension::COMPONENT) |
| 3170 return true; | 3306 return true; |
| 3171 | |
| 3172 bool access_denied = false; | 3307 bool access_denied = false; |
| 3173 if (permission->HasWhitelist()) { | 3308 if (permission->HasWhitelist()) { |
| 3174 if (permission->IsWhitelisted(id())) | 3309 if (permission->IsWhitelisted(id())) |
| 3175 return true; | 3310 return true; |
| 3176 else | 3311 else |
| 3177 access_denied = true; | 3312 access_denied = true; |
| 3178 } else if (permission->is_component_only()) { | 3313 } else if (permission->is_component_only()) { |
| 3179 access_denied = true; | 3314 access_denied = true; |
| 3180 } | 3315 } |
| 3181 | 3316 |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3339 return SYNC_TYPE_APP; | 3474 return SYNC_TYPE_APP; |
| 3340 | 3475 |
| 3341 default: | 3476 default: |
| 3342 return SYNC_TYPE_NONE; | 3477 return SYNC_TYPE_NONE; |
| 3343 } | 3478 } |
| 3344 } | 3479 } |
| 3345 | 3480 |
| 3346 bool Extension::IsSyncable() const { | 3481 bool Extension::IsSyncable() const { |
| 3347 // TODO(akalin): Figure out if we need to allow some other types. | 3482 // TODO(akalin): Figure out if we need to allow some other types. |
| 3348 | 3483 |
| 3349 // We want to sync any extensions that are shown in the luancher because | 3484 // We want to sync any extensions that are shown in the launcher because |
| 3350 // their positions should sync. | 3485 // their positions should sync. |
| 3351 return location() == Extension::INTERNAL || | 3486 return location() == Extension::INTERNAL || |
| 3352 ShouldDisplayInLauncher(); | 3487 ShouldDisplayInLauncher(); |
| 3353 } | 3488 } |
| 3354 | 3489 |
| 3355 bool Extension::ShouldDisplayInLauncher() const { | 3490 bool Extension::ShouldDisplayInLauncher() const { |
| 3356 // All apps should be displayed on the NTP except for the Cloud Print App. | 3491 // All apps should be displayed on the NTP except for the Cloud Print App. |
| 3357 return is_app() && id() != extension_misc::kCloudPrintAppId; | 3492 return is_app() && id() != extension_misc::kCloudPrintAppId; |
| 3358 } | 3493 } |
| 3359 | 3494 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3392 already_disabled(false), | 3527 already_disabled(false), |
| 3393 extension(extension) {} | 3528 extension(extension) {} |
| 3394 | 3529 |
| 3395 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3530 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
| 3396 const Extension* extension, | 3531 const Extension* extension, |
| 3397 const ExtensionPermissionSet* permissions, | 3532 const ExtensionPermissionSet* permissions, |
| 3398 Reason reason) | 3533 Reason reason) |
| 3399 : reason(reason), | 3534 : reason(reason), |
| 3400 extension(extension), | 3535 extension(extension), |
| 3401 permissions(permissions) {} | 3536 permissions(permissions) {} |
| OLD | NEW |