Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/extensions/extension.h" | 5 #include "chrome/common/extensions/extension.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 utf8_error); | 326 utf8_error); |
| 327 } | 327 } |
| 328 | 328 |
| 329 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 329 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
| 330 Location location, | 330 Location location, |
| 331 const DictionaryValue& value, | 331 const DictionaryValue& value, |
| 332 int flags, | 332 int flags, |
| 333 const std::string& explicit_id, | 333 const std::string& explicit_id, |
| 334 std::string* utf8_error) { | 334 std::string* utf8_error) { |
| 335 DCHECK(utf8_error); | 335 DCHECK(utf8_error); |
| 336 | |
| 337 string16 error; | 336 string16 error; |
| 338 scoped_ptr<extensions::Manifest> manifest( | 337 scoped_ptr<extensions::Manifest> manifest( |
| 339 new extensions::Manifest( | 338 new extensions::Manifest( |
| 340 location, | 339 location, |
| 341 scoped_ptr<DictionaryValue>(value.DeepCopy()))); | 340 scoped_ptr<DictionaryValue>(value.DeepCopy()))); |
| 342 | 341 |
| 343 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error) || | 342 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error) || |
| 344 !manifest->ValidateManifest(&error)) { | 343 !manifest->ValidateManifest(&error)) { |
| 345 *utf8_error = UTF16ToUTF8(error); | 344 *utf8_error = UTF16ToUTF8(error); |
| 346 return NULL; | 345 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)); | 472 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false)); |
| 474 | 473 |
| 475 return ret_val; | 474 return ret_val; |
| 476 } | 475 } |
| 477 | 476 |
| 478 bool Extension::is_platform_app() const { | 477 bool Extension::is_platform_app() const { |
| 479 return manifest_->IsPlatformApp(); | 478 return manifest_->IsPlatformApp(); |
| 480 } | 479 } |
| 481 | 480 |
| 482 bool Extension::is_hosted_app() const { | 481 bool Extension::is_hosted_app() const { |
| 483 return manifest()->IsHostedApp(); | 482 return manifest()->IsHostedApp(); |
| 484 } | 483 } |
| 485 | 484 |
| 486 bool Extension::is_packaged_app() const { | 485 bool Extension::is_packaged_app() const { |
| 487 return manifest()->IsPackagedApp(); | 486 return manifest()->IsPackagedApp(); |
| 488 } | 487 } |
| 489 | 488 |
| 490 bool Extension::is_theme() const { | 489 bool Extension::is_theme() const { |
| 491 return manifest()->IsTheme(); | 490 return manifest()->IsTheme(); |
| 492 } | 491 } |
| 493 | 492 |
| 494 GURL Extension::GetBackgroundURL() const { | 493 GURL Extension::GetBackgroundURL() const { |
| 495 if (!background_scripts_.empty()) { | 494 if (!background_scripts_.empty()) { |
| 496 return GetResourceURL( | 495 return GetResourceURL( |
| 497 extension_filenames::kGeneratedBackgroundPageFilename); | 496 extension_filenames::kGeneratedBackgroundPageFilename); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 528 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash))); | 527 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash))); |
| 529 ConvertHexadecimalToIDAlphabet(output); | 528 ConvertHexadecimalToIDAlphabet(output); |
| 530 | 529 |
| 531 return true; | 530 return true; |
| 532 } | 531 } |
| 533 | 532 |
| 534 // Helper method that loads a UserScript object from a dictionary in the | 533 // Helper method that loads a UserScript object from a dictionary in the |
| 535 // content_script list of the manifest. | 534 // content_script list of the manifest. |
| 536 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, | 535 bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, |
| 537 int definition_index, | 536 int definition_index, |
| 538 int flags, | |
| 539 string16* error, | 537 string16* error, |
| 540 UserScript* result) { | 538 UserScript* result) { |
| 541 // run_at | 539 // run_at |
| 542 if (content_script->HasKey(keys::kRunAt)) { | 540 if (content_script->HasKey(keys::kRunAt)) { |
| 543 std::string run_location; | 541 std::string run_location; |
| 544 if (!content_script->GetString(keys::kRunAt, &run_location)) { | 542 if (!content_script->GetString(keys::kRunAt, &run_location)) { |
| 545 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 543 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 546 errors::kInvalidRunAt, | 544 errors::kInvalidRunAt, |
| 547 base::IntToString(definition_index)); | 545 base::IntToString(definition_index)); |
| 548 return false; | 546 return false; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 609 errors::kInvalidMatch, | 607 errors::kInvalidMatch, |
| 610 base::IntToString(definition_index), | 608 base::IntToString(definition_index), |
| 611 base::IntToString(j), | 609 base::IntToString(j), |
| 612 URLPattern::GetParseResultString(parse_result)); | 610 URLPattern::GetParseResultString(parse_result)); |
| 613 return false; | 611 return false; |
| 614 } | 612 } |
| 615 | 613 |
| 616 if (pattern.MatchesScheme(chrome::kFileScheme) && | 614 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 617 !CanExecuteScriptEverywhere()) { | 615 !CanExecuteScriptEverywhere()) { |
| 618 wants_file_access_ = true; | 616 wants_file_access_ = true; |
| 619 if (!(flags & ALLOW_FILE_ACCESS)) | 617 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) |
| 620 pattern.SetValidSchemes( | 618 pattern.SetValidSchemes( |
| 621 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 619 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 622 } | 620 } |
| 623 | 621 |
| 624 result->add_url_pattern(pattern); | 622 result->add_url_pattern(pattern); |
| 625 } | 623 } |
| 626 | 624 |
| 627 // exclude_matches | 625 // exclude_matches |
| 628 if (content_script->HasKey(keys::kExcludeMatches)) { // optional | 626 if (content_script->HasKey(keys::kExcludeMatches)) { // optional |
| 629 ListValue* exclude_matches = NULL; | 627 ListValue* exclude_matches = NULL; |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 885 result->SetPopupUrl(ExtensionAction::kDefaultTabId, url); | 883 result->SetPopupUrl(ExtensionAction::kDefaultTabId, url); |
| 886 } else { | 884 } else { |
| 887 DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId)) | 885 DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId)) |
| 888 << "Shouldn't be possible for the popup to be set."; | 886 << "Shouldn't be possible for the popup to be set."; |
| 889 } | 887 } |
| 890 } | 888 } |
| 891 | 889 |
| 892 return result.release(); | 890 return result.release(); |
| 893 } | 891 } |
| 894 | 892 |
| 895 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlers( | 893 // static |
| 896 const ListValue* extension_actions, string16* error) { | 894 bool Extension::InitExtensionID(extensions::Manifest* manifest, |
| 897 scoped_ptr<FileBrowserHandlerList> result( | 895 const FilePath& path, |
| 898 new FileBrowserHandlerList()); | 896 const std::string& explicit_id, |
| 899 for (ListValue::const_iterator iter = extension_actions->begin(); | 897 int creation_flags, |
| 900 iter != extension_actions->end(); | 898 string16* error) { |
| 901 ++iter) { | 899 if (!explicit_id.empty()) { |
| 902 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) { | 900 manifest->set_extension_id(explicit_id); |
| 903 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | 901 return true; |
| 904 return NULL; | 902 } |
| 903 | |
| 904 if (manifest->HasKey(keys::kPublicKey)) { | |
| 905 std::string public_key; | |
| 906 std::string public_key_bytes; | |
| 907 std::string extension_id; | |
| 908 if (!manifest->GetString(keys::kPublicKey, &public_key) || | |
| 909 !ParsePEMKeyBytes(public_key, &public_key_bytes) || | |
| 910 !GenerateId(public_key_bytes, &extension_id)) { | |
| 911 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 912 return false; | |
| 905 } | 913 } |
| 906 scoped_ptr<FileBrowserHandler> action( | 914 manifest->set_extension_id(extension_id); |
| 907 LoadFileBrowserHandler( | 915 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 } | 916 } |
| 913 return result.release(); | 917 |
| 918 if (creation_flags & REQUIRE_KEY) { | |
| 919 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 920 return false; | |
| 921 } else { | |
| 922 // If there is a path, we generate the ID from it. This is useful for | |
| 923 // development mode, because it keeps the ID stable across restarts and | |
| 924 // reloading the extension. | |
| 925 std::string extension_id = GenerateIdForPath(path); | |
| 926 if (extension_id.empty()) { | |
| 927 NOTREACHED() << "Could not create ID from path."; | |
| 928 return false; | |
| 929 } | |
| 930 manifest->set_extension_id(extension_id); | |
| 931 return true; | |
| 932 } | |
| 914 } | 933 } |
| 915 | 934 |
| 916 FileBrowserHandler* Extension::LoadFileBrowserHandler( | 935 bool Extension::CheckMinimumChromeVersion(string16* error) { |
| 917 const DictionaryValue* file_browser_handler, string16* error) { | 936 if (!manifest_->HasKey(keys::kMinimumChromeVersion)) |
| 918 scoped_ptr<FileBrowserHandler> result( | 937 return true; |
| 919 new FileBrowserHandler()); | 938 std::string minimum_version_string; |
| 920 result->set_extension_id(id()); | 939 if (!manifest_->GetString(keys::kMinimumChromeVersion, |
| 921 | 940 &minimum_version_string)) { |
| 922 std::string id; | 941 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); |
| 923 // Read the file action |id| (mandatory). | 942 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 } | 943 } |
| 973 | 944 |
| 974 std::string default_icon; | 945 scoped_ptr<Version> minimum_version( |
| 975 // Read the file browser action |default_icon| (optional). | 946 Version::GetVersionFromString(minimum_version_string)); |
| 976 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { | 947 if (!minimum_version.get()) { |
| 977 if (!file_browser_handler->GetString( | 948 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); |
| 978 keys::kPageActionDefaultIcon, &default_icon) || | 949 return false; |
| 979 default_icon.empty()) { | |
| 980 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | |
| 981 return NULL; | |
| 982 } | |
| 983 result->set_icon_path(default_icon); | |
| 984 } | 950 } |
| 985 | 951 |
| 986 return result.release(); | 952 chrome::VersionInfo current_version_info; |
| 953 if (!current_version_info.is_valid()) { | |
| 954 NOTREACHED(); | |
| 955 return false; | |
| 956 } | |
| 957 | |
| 958 scoped_ptr<Version> current_version( | |
| 959 Version::GetVersionFromString(current_version_info.Version())); | |
| 960 if (!current_version.get()) { | |
| 961 DCHECK(false); | |
| 962 return false; | |
| 963 } | |
| 964 | |
| 965 if (current_version->CompareTo(*minimum_version) < 0) { | |
| 966 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 967 errors::kChromeVersionTooLow, | |
| 968 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME), | |
| 969 minimum_version_string); | |
| 970 return false; | |
| 971 } | |
| 972 return true; | |
| 973 } | |
| 974 | |
| 975 bool Extension::LoadRequiredFeatures(string16* error) { | |
|
Yoyo Zhou
2012/03/02 20:20:07
So, the required features are actually name and ve
Devlin
2012/03/07 04:18:54
Done.
| |
| 976 if (!LoadName(error) || | |
| 977 !LoadDescription(error)) | |
| 978 return false; | |
| 979 return true; | |
| 980 } | |
| 981 | |
| 982 bool Extension::LoadName(string16* error) { | |
| 983 string16 localized_name; | |
| 984 if (!manifest_->GetString(keys::kName, &localized_name)) { | |
| 985 *error = ASCIIToUTF16(errors::kInvalidName); | |
| 986 return false; | |
| 987 } | |
| 988 base::i18n::AdjustStringForLocaleDirection(&localized_name); | |
| 989 name_ = UTF16ToUTF8(localized_name); | |
| 990 return true; | |
| 991 } | |
| 992 | |
| 993 bool Extension::LoadDescription(string16* error) { | |
| 994 if (manifest_->HasKey(keys::kDescription) && | |
| 995 !manifest_->GetString(keys::kDescription, &description_)) { | |
| 996 *error = ASCIIToUTF16(errors::kInvalidDescription); | |
| 997 return false; | |
| 998 } | |
| 999 return true; | |
| 1000 } | |
| 1001 | |
| 1002 bool Extension::LoadAppFeatures(string16* error) { | |
| 1003 if (!LoadExtent(keys::kWebURLs, &extent_, | |
| 1004 errors::kInvalidWebURLs, errors::kInvalidWebURL, error) || | |
| 1005 !LoadLaunchURL(error) || | |
| 1006 !LoadLaunchContainer(error)) | |
| 1007 return false; | |
| 1008 | |
| 1009 if (is_platform_app()) { | |
|
Yoyo Zhou
2012/03/02 20:20:07
This block looks like it should go in LoadLaunchCo
Devlin
2012/03/07 04:18:54
Done.
| |
| 1010 if (launch_container() != extension_misc::LAUNCH_SHELL) { | |
|
Yoyo Zhou
2012/03/02 20:20:07
style nit: Can you change these to launch_containe
Devlin
2012/03/07 04:18:54
Done.
| |
| 1011 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform); | |
| 1012 return false; | |
| 1013 } | |
| 1014 } else if (launch_container() == extension_misc::LAUNCH_SHELL) { | |
| 1015 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform); | |
| 1016 return false; | |
| 1017 } | |
| 1018 | |
| 1019 return true; | |
| 987 } | 1020 } |
| 988 | 1021 |
| 989 bool Extension::LoadExtent(const char* key, | 1022 bool Extension::LoadExtent(const char* key, |
| 990 URLPatternSet* extent, | 1023 URLPatternSet* extent, |
| 991 const char* list_error, | 1024 const char* list_error, |
| 992 const char* value_error, | 1025 const char* value_error, |
| 993 string16* error) { | 1026 string16* error) { |
| 994 Value* temp = NULL; | 1027 Value* temp = NULL; |
| 995 if (!manifest_->Get(key, &temp)) | 1028 if (!manifest_->Get(key, &temp)) |
| 996 return true; | 1029 return true; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1160 GURL::Replacements replacements; | 1193 GURL::Replacements replacements; |
| 1161 replacements.SetPathStr(path); | 1194 replacements.SetPathStr(path); |
| 1162 GURL cloud_print_enable_connector_url = | 1195 GURL cloud_print_enable_connector_url = |
| 1163 cloud_print_service_url.ReplaceComponents(replacements); | 1196 cloud_print_service_url.ReplaceComponents(replacements); |
| 1164 OverrideLaunchUrl(cloud_print_enable_connector_url); | 1197 OverrideLaunchUrl(cloud_print_enable_connector_url); |
| 1165 } | 1198 } |
| 1166 } | 1199 } |
| 1167 return true; | 1200 return true; |
| 1168 } | 1201 } |
| 1169 | 1202 |
| 1170 bool ReadLaunchDimension(const extensions::Manifest* manifest, | 1203 bool ReadLaunchDimension(const extensions::Manifest* manifest, |
|
Yoyo Zhou
2012/03/02 20:20:07
Functions like this should go in the anonymous nam
Devlin
2012/03/07 04:18:54
Done.
| |
| 1171 const char* key, | 1204 const char* key, |
| 1172 int* target, | 1205 int* target, |
| 1173 bool is_valid_container, | 1206 bool is_valid_container, |
| 1174 string16* error) { | 1207 string16* error) { |
| 1175 Value* temp = NULL; | 1208 Value* temp = NULL; |
| 1176 if (manifest->Get(key, &temp)) { | 1209 if (manifest->Get(key, &temp)) { |
| 1177 if (!is_valid_container) { | 1210 if (!is_valid_container) { |
| 1178 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1211 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1179 errors::kInvalidLaunchValueContainer, | 1212 errors::kInvalidLaunchValueContainer, |
| 1180 key); | 1213 key); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1286 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1319 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1287 errors::kInvalidLaunchValue, | 1320 errors::kInvalidLaunchValue, |
| 1288 keys::kLaunchMaxHeight); | 1321 keys::kLaunchMaxHeight); |
| 1289 return false; | 1322 return false; |
| 1290 } | 1323 } |
| 1291 } | 1324 } |
| 1292 | 1325 |
| 1293 return true; | 1326 return true; |
| 1294 } | 1327 } |
| 1295 | 1328 |
| 1296 bool Extension::LoadAppIsolation(string16* error) { | 1329 bool Extension::LoadSharedFeatures( |
| 1297 Value* temp = NULL; | 1330 const ExtensionAPIPermissionSet& api_permissions, |
| 1298 if (!manifest_->Get(keys::kIsolation, &temp)) | 1331 string16* error) { |
| 1299 return true; | 1332 if (!LoadVersion(error) || |
| 1300 | 1333 !LoadManifestVersion(error) || |
| 1301 if (temp->GetType() != Value::TYPE_LIST) { | 1334 !LoadHomepageURL(error) || |
| 1302 *error = ASCIIToUTF16(errors::kInvalidIsolation); | 1335 !LoadUpdateURL(error) || |
| 1303 return false; | 1336 !LoadIcons(error) || |
| 1304 } | 1337 !LoadCommands(error) || |
| 1305 | 1338 !LoadPlugins(error) || |
| 1306 ListValue* isolation_list = static_cast<ListValue*>(temp); | 1339 !LoadNaClModules(error) || |
| 1307 for (size_t i = 0; i < isolation_list->GetSize(); ++i) { | 1340 !LoadWebAccessibleResources(error) || |
| 1308 std::string isolation_string; | 1341 !LoadRequirements(error) || |
| 1309 if (!isolation_list->GetString(i, &isolation_string)) { | 1342 !LoadDefaultLocale(error) || |
| 1310 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1343 !LoadOfflineEnabled(error) || |
| 1311 errors::kInvalidIsolationValue, | 1344 !LoadOptionsPage(error) || |
| 1312 base::UintToString(i)); | 1345 // LoadBackgroundScripts() must be called before LoadBackgroundPage(). |
| 1313 return false; | 1346 !LoadBackgroundScripts(error) || |
| 1314 } | 1347 !LoadBackgroundPage(api_permissions, error) || |
| 1315 | 1348 !LoadBackgroundPersistent(api_permissions, error) || |
| 1316 // Check for isolated storage. | 1349 !LoadWebIntentServices(error)) |
| 1317 if (isolation_string == values::kIsolatedStorage) { | 1350 return false; |
| 1318 is_storage_isolated_ = true; | 1351 |
| 1319 } else { | 1352 return true; |
| 1320 DLOG(WARNING) << "Did not recognize isolation type: " | 1353 } |
| 1321 << isolation_string; | 1354 |
| 1322 } | 1355 bool Extension::LoadVersion(string16* error) { |
| 1323 } | 1356 std::string version_str; |
| 1324 return true; | 1357 if (!manifest_->GetString(keys::kVersion, &version_str)) { |
| 1325 } | 1358 *error = ASCIIToUTF16(errors::kInvalidVersion); |
| 1326 | 1359 return false; |
| 1327 bool Extension::LoadWebIntentServices(string16* error) { | 1360 } |
| 1328 DCHECK(error); | 1361 version_.reset(Version::GetVersionFromString(version_str)); |
| 1329 | 1362 if (!version_.get() || |
| 1330 if (!manifest_->HasKey(keys::kIntents)) | 1363 version_->components().size() > 4) { |
| 1331 return true; | 1364 *error = ASCIIToUTF16(errors::kInvalidVersion); |
| 1332 | 1365 return false; |
| 1333 DictionaryValue* all_services = NULL; | 1366 } |
| 1334 if (!manifest_->GetDictionary(keys::kIntents, &all_services)) { | 1367 return true; |
| 1335 *error = ASCIIToUTF16(errors::kInvalidIntents); | 1368 } |
| 1336 return false; | 1369 |
| 1337 } | 1370 bool Extension::LoadManifestVersion(string16* error) { |
| 1338 | 1371 // Get the original value out of the dictionary so that we can validate it |
| 1339 std::string value; | 1372 // more strictly. |
| 1340 for (DictionaryValue::key_iterator iter(all_services->begin_keys()); | 1373 if (manifest_->value()->HasKey(keys::kManifestVersion)) { |
| 1341 iter != all_services->end_keys(); ++iter) { | 1374 int manifest_version = 1; |
| 1342 webkit_glue::WebIntentServiceData service; | 1375 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) || |
| 1343 | 1376 manifest_version < 1) { |
| 1344 DictionaryValue* one_service = NULL; | 1377 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); |
| 1345 if (!all_services->GetDictionaryWithoutPathExpansion(*iter, &one_service)) { | 1378 return false; |
| 1346 *error = ASCIIToUTF16(errors::kInvalidIntent); | 1379 } |
| 1347 return false; | 1380 } |
| 1348 } | 1381 |
| 1349 service.action = UTF8ToUTF16(*iter); | 1382 manifest_version_ = manifest_->GetManifestVersion(); |
| 1350 | 1383 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION && |
| 1351 ListValue* mime_types = NULL; | 1384 manifest_version_ < kModernManifestVersion && |
| 1352 if (!one_service->HasKey(keys::kIntentType) || | 1385 !CommandLine::ForCurrentProcess()->HasSwitch( |
| 1353 !one_service->GetList(keys::kIntentType, &mime_types) || | 1386 switches::kAllowLegacyExtensionManifests)) { |
| 1354 mime_types->GetSize() == 0) { | 1387 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); |
| 1355 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1388 return false; |
| 1356 errors::kInvalidIntentType, *iter); | 1389 } |
| 1357 return false; | 1390 |
| 1358 } | 1391 return true; |
| 1359 | 1392 } |
| 1360 if (one_service->HasKey(keys::kIntentPath)) { | 1393 |
| 1361 if (!one_service->GetString(keys::kIntentPath, &value)) { | 1394 bool Extension::LoadHomepageURL(string16* error) { |
| 1362 *error = ASCIIToUTF16(errors::kInvalidIntentPath); | 1395 if (!manifest_->HasKey(keys::kHomepageURL)) |
| 1396 return true; | |
| 1397 std::string tmp; | |
| 1398 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) { | |
| 1399 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1400 errors::kInvalidHomepageURL, ""); | |
| 1401 return false; | |
| 1402 } | |
| 1403 homepage_url_ = GURL(tmp); | |
| 1404 if (!homepage_url_.is_valid() || | |
| 1405 (!homepage_url_.SchemeIs("http") && | |
| 1406 !homepage_url_.SchemeIs("https"))) { | |
| 1407 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1408 errors::kInvalidHomepageURL, tmp); | |
| 1409 return false; | |
| 1410 } | |
| 1411 return true; | |
| 1412 } | |
| 1413 | |
| 1414 bool Extension::LoadUpdateURL(string16* error) { | |
| 1415 if (!manifest_->HasKey(keys::kUpdateURL)) | |
| 1416 return true; | |
| 1417 std::string tmp; | |
| 1418 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) { | |
| 1419 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1420 errors::kInvalidUpdateURL, ""); | |
| 1421 return false; | |
| 1422 } | |
| 1423 update_url_ = GURL(tmp); | |
| 1424 if (!update_url_.is_valid() || | |
| 1425 update_url_.has_ref()) { | |
| 1426 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1427 errors::kInvalidUpdateURL, tmp); | |
| 1428 return false; | |
| 1429 } | |
| 1430 return true; | |
| 1431 } | |
| 1432 | |
| 1433 bool Extension::LoadIcons(string16* error) { | |
| 1434 if (!manifest_->HasKey(keys::kIcons)) | |
| 1435 return true; | |
| 1436 DictionaryValue* icons_value = NULL; | |
| 1437 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) { | |
| 1438 *error = ASCIIToUTF16(errors::kInvalidIcons); | |
| 1439 return false; | |
| 1440 } | |
| 1441 | |
| 1442 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) { | |
| 1443 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]); | |
| 1444 if (icons_value->HasKey(key)) { | |
| 1445 std::string icon_path; | |
| 1446 if (!icons_value->GetString(key, &icon_path)) { | |
| 1447 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1448 errors::kInvalidIconPath, key); | |
| 1363 return false; | 1449 return false; |
| 1364 } | 1450 } |
| 1365 if (is_hosted_app()) { | 1451 |
| 1366 // Hosted apps require an absolute URL for intents. | 1452 if (!icon_path.empty() && icon_path[0] == '/') |
| 1367 GURL service_url(value); | 1453 icon_path = icon_path.substr(1); |
| 1368 if (!service_url.is_valid() || | 1454 |
| 1369 !(web_extent().MatchesURL(service_url))) { | 1455 if (icon_path.empty()) { |
| 1370 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1456 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1371 errors::kInvalidIntentPageInHostedApp, *iter); | 1457 errors::kInvalidIconPath, key); |
| 1372 return false; | |
| 1373 } | |
| 1374 service.service_url = service_url; | |
| 1375 } else { | |
| 1376 // We do not allow absolute intent URLs in non-hosted apps. | |
| 1377 if (GURL(value).is_valid()) { | |
| 1378 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1379 errors::kCannotAccessPage, value.c_str()); | |
| 1380 return false; | |
| 1381 } | |
| 1382 service.service_url = GetResourceURL(value); | |
| 1383 } | |
| 1384 } | |
| 1385 | |
| 1386 if (one_service->HasKey(keys::kIntentTitle) && | |
| 1387 !one_service->GetString(keys::kIntentTitle, &service.title)) { | |
| 1388 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | |
| 1389 return false; | |
| 1390 } | |
| 1391 | |
| 1392 if (one_service->HasKey(keys::kIntentDisposition)) { | |
| 1393 if (!one_service->GetString(keys::kIntentDisposition, &value) || | |
| 1394 (value != values::kIntentDispositionWindow && | |
| 1395 value != values::kIntentDispositionInline)) { | |
| 1396 *error = ASCIIToUTF16(errors::kInvalidIntentDisposition); | |
| 1397 return false; | 1458 return false; |
| 1398 } | 1459 } |
| 1399 if (value == values::kIntentDispositionInline) { | 1460 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path); |
| 1400 service.disposition = | 1461 } |
| 1401 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; | 1462 } |
| 1402 } else { | 1463 return true; |
| 1403 service.disposition = | 1464 } |
| 1404 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW; | 1465 |
| 1405 } | 1466 bool Extension::LoadCommands(string16* error) { |
| 1406 } | 1467 if (manifest_->HasKey(keys::kCommands)) { |
| 1407 | 1468 DictionaryValue* commands = NULL; |
| 1408 for (size_t i = 0; i < mime_types->GetSize(); ++i) { | 1469 if (!manifest_->GetDictionary(keys::kCommands, &commands)) { |
| 1409 if (!mime_types->GetString(i, &service.type)) { | 1470 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); |
| 1471 return false; | |
| 1472 } | |
| 1473 | |
| 1474 int command_index = 0; | |
| 1475 for (DictionaryValue::key_iterator iter = commands->begin_keys(); | |
| 1476 iter != commands->end_keys(); ++iter) { | |
| 1477 ++command_index; | |
| 1478 | |
| 1479 DictionaryValue* command = NULL; | |
| 1480 if (!commands->GetDictionary(*iter, &command)) { | |
| 1410 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1481 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1411 errors::kInvalidIntentTypeElement, *iter, | 1482 errors::kInvalidKeyBindingDictionary, |
| 1412 std::string(base::IntToString(i))); | 1483 base::IntToString(command_index)); |
| 1413 return false; | 1484 return false; |
| 1414 } | 1485 } |
| 1415 intents_services_.push_back(service); | 1486 |
| 1416 } | 1487 ExtensionKeybinding binding; |
| 1417 } | 1488 if (!binding.Parse(command, *iter, command_index, error)) |
| 1418 return true; | 1489 return false; // |error| already set. |
| 1419 } | 1490 |
| 1420 | 1491 commands_.push_back(binding); |
| 1492 } | |
| 1493 } | |
| 1494 return true; | |
| 1495 } | |
| 1496 | |
| 1497 bool Extension::LoadPlugins(string16* error) { | |
| 1498 if (!manifest_->HasKey(keys::kPlugins)) | |
| 1499 return true; | |
| 1500 ListValue* list_value = NULL; | |
| 1501 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | |
| 1502 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 1503 return false; | |
| 1504 } | |
| 1505 | |
| 1506 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1507 DictionaryValue* plugin_value = NULL; | |
| 1508 std::string path_str; | |
| 1509 bool is_public = false; | |
| 1510 if (!list_value->GetDictionary(i, &plugin_value)) { | |
| 1511 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 1512 return false; | |
| 1513 } | |
| 1514 // Get plugins[i].path. | |
| 1515 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) { | |
| 1516 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1517 errors::kInvalidPluginsPath, base::IntToString(i)); | |
| 1518 return false; | |
| 1519 } | |
| 1520 | |
| 1521 // Get plugins[i].content (optional). | |
| 1522 if (plugin_value->HasKey(keys::kPluginsPublic)) { | |
| 1523 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) { | |
| 1524 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1525 errors::kInvalidPluginsPublic, base::IntToString(i)); | |
| 1526 return false; | |
| 1527 } | |
| 1528 } | |
| 1529 | |
| 1530 // We don't allow extension plugins to run on Chrome OS. We still | |
| 1531 // parse the manifest entry so that error messages are consistently | |
| 1532 // displayed across platforms. | |
| 1533 #if !defined(OS_CHROMEOS) | |
| 1534 plugins_.push_back(PluginInfo()); | |
| 1535 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str)); | |
| 1536 plugins_.back().is_public = is_public; | |
| 1537 #endif | |
| 1538 } | |
| 1539 return true; | |
| 1540 } | |
| 1541 | |
| 1542 bool Extension::LoadNaClModules(string16* error) { | |
| 1543 if (!manifest_->HasKey(keys::kNaClModules)) | |
| 1544 return true; | |
| 1545 ListValue* list_value = NULL; | |
| 1546 if (!manifest_->GetList(keys::kNaClModules, &list_value)) { | |
| 1547 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 1548 return false; | |
| 1549 } | |
| 1550 | |
| 1551 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1552 DictionaryValue* module_value = NULL; | |
| 1553 std::string path_str; | |
| 1554 std::string mime_type; | |
| 1555 | |
| 1556 if (!list_value->GetDictionary(i, &module_value)) { | |
| 1557 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 1558 return false; | |
| 1559 } | |
| 1560 | |
| 1561 // Get nacl_modules[i].path. | |
| 1562 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) { | |
| 1563 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1564 errors::kInvalidNaClModulesPath, base::IntToString(i)); | |
| 1565 return false; | |
| 1566 } | |
| 1567 | |
| 1568 // Get nacl_modules[i].mime_type. | |
| 1569 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) { | |
| 1570 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1571 errors::kInvalidNaClModulesMIMEType, base::IntToString(i)); | |
| 1572 return false; | |
| 1573 } | |
| 1574 | |
| 1575 nacl_modules_.push_back(NaClModuleInfo()); | |
| 1576 nacl_modules_.back().url = GetResourceURL(path_str); | |
| 1577 nacl_modules_.back().mime_type = mime_type; | |
| 1578 } | |
| 1579 | |
| 1580 return true; | |
| 1581 } | |
| 1582 | |
| 1583 bool Extension::LoadWebAccessibleResources(string16* error) { | |
| 1584 if (!manifest_->HasKey(keys::kWebAccessibleResources)) | |
| 1585 return true; | |
| 1586 ListValue* list_value; | |
| 1587 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) { | |
| 1588 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList); | |
| 1589 return false; | |
| 1590 } | |
| 1591 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1592 std::string relative_path; | |
| 1593 if (!list_value->GetString(i, &relative_path)) { | |
| 1594 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1595 errors::kInvalidWebAccessibleResource, base::IntToString(i)); | |
| 1596 return false; | |
| 1597 } | |
| 1598 if (relative_path[0] != '/') | |
| 1599 relative_path = '/' + relative_path; | |
| 1600 web_accessible_resources_.insert(relative_path); | |
| 1601 } | |
| 1602 | |
| 1603 return true; | |
| 1604 } | |
| 1605 | |
| 1606 // These are not actually persisted (they're only used by the store), but | |
| 1607 // still validated. | |
| 1608 bool Extension::LoadRequirements(string16* error) { | |
|
Yoyo Zhou
2012/03/02 20:20:07
Likewise I might rename this one to CheckRequireme
Devlin
2012/03/07 04:18:54
Done.
| |
| 1609 if (!manifest_->HasKey(keys::kRequirements)) | |
| 1610 return true; | |
| 1611 DictionaryValue* requirements_value = NULL; | |
| 1612 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) { | |
| 1613 *error = ASCIIToUTF16(errors::kInvalidRequirements); | |
| 1614 return false; | |
| 1615 } | |
| 1616 | |
| 1617 for (DictionaryValue::key_iterator it = requirements_value->begin_keys(); | |
| 1618 it != requirements_value->end_keys(); ++it) { | |
| 1619 DictionaryValue* requirement_value; | |
| 1620 if (!requirements_value->GetDictionaryWithoutPathExpansion( | |
| 1621 *it, &requirement_value)) { | |
| 1622 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1623 errors::kInvalidRequirement, *it); | |
| 1624 return false; | |
| 1625 } | |
| 1626 } | |
| 1627 return true; | |
| 1628 } | |
| 1629 | |
| 1630 bool Extension::LoadDefaultLocale(string16* error) { | |
| 1631 if (!manifest_->HasKey(keys::kDefaultLocale)) | |
| 1632 return true; | |
| 1633 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) || | |
| 1634 !l10n_util::IsValidLocaleSyntax(default_locale_)) { | |
| 1635 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale); | |
| 1636 return false; | |
| 1637 } | |
| 1638 return true; | |
| 1639 } | |
| 1640 | |
| 1641 bool Extension::LoadOfflineEnabled(string16* error) { | |
| 1642 // Defaults to false. | |
| 1643 if (manifest_->HasKey(keys::kOfflineEnabled) && | |
| 1644 !manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { | |
| 1645 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled); | |
| 1646 return false; | |
| 1647 } | |
| 1648 return true; | |
| 1649 } | |
| 1650 | |
| 1651 bool Extension::LoadOptionsPage(string16* error) { | |
| 1652 if (!manifest_->HasKey(keys::kOptionsPage)) | |
| 1653 return true; | |
| 1654 std::string options_str; | |
| 1655 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) { | |
| 1656 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 1657 return false; | |
| 1658 } | |
| 1659 | |
| 1660 if (is_hosted_app()) { | |
| 1661 // hosted apps require an absolute URL. | |
| 1662 GURL options_url(options_str); | |
| 1663 if (!options_url.is_valid() || | |
| 1664 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) { | |
| 1665 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp); | |
| 1666 return false; | |
| 1667 } | |
| 1668 options_url_ = options_url; | |
| 1669 } else { | |
| 1670 GURL absolute(options_str); | |
| 1671 if (absolute.is_valid()) { | |
| 1672 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage); | |
| 1673 return false; | |
| 1674 } | |
| 1675 options_url_ = GetResourceURL(options_str); | |
| 1676 if (!options_url_.is_valid()) { | |
| 1677 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 1678 return false; | |
| 1679 } | |
| 1680 } | |
| 1681 | |
| 1682 return true; | |
| 1683 } | |
| 1684 | |
| 1421 bool Extension::LoadBackgroundScripts(string16* error) { | 1685 bool Extension::LoadBackgroundScripts(string16* error) { |
| 1422 Value* background_scripts_value = NULL; | 1686 Value* background_scripts_value = NULL; |
| 1423 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) | 1687 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) |
| 1424 return true; | 1688 return true; |
| 1425 | 1689 |
| 1426 CHECK(background_scripts_value); | 1690 CHECK(background_scripts_value); |
| 1427 if (background_scripts_value->GetType() != Value::TYPE_LIST) { | 1691 if (background_scripts_value->GetType() != Value::TYPE_LIST) { |
| 1428 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); | 1692 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); |
| 1429 return false; | 1693 return false; |
| 1430 } | 1694 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1508 } | 1772 } |
| 1509 | 1773 |
| 1510 if (!has_background_page()) { | 1774 if (!has_background_page()) { |
| 1511 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); | 1775 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); |
| 1512 return false; | 1776 return false; |
| 1513 } | 1777 } |
| 1514 | 1778 |
| 1515 return true; | 1779 return true; |
| 1516 } | 1780 } |
| 1517 | 1781 |
| 1782 bool Extension::LoadWebIntentServices(string16* error) { | |
| 1783 DCHECK(error); | |
| 1784 | |
| 1785 if (!manifest_->HasKey(keys::kIntents)) | |
| 1786 return true; | |
| 1787 | |
| 1788 DictionaryValue* all_services = NULL; | |
| 1789 if (!manifest_->GetDictionary(keys::kIntents, &all_services)) { | |
| 1790 *error = ASCIIToUTF16(errors::kInvalidIntents); | |
| 1791 return false; | |
| 1792 } | |
| 1793 | |
| 1794 std::string value; | |
| 1795 for (DictionaryValue::key_iterator iter(all_services->begin_keys()); | |
| 1796 iter != all_services->end_keys(); ++iter) { | |
| 1797 webkit_glue::WebIntentServiceData service; | |
| 1798 | |
| 1799 DictionaryValue* one_service = NULL; | |
| 1800 if (!all_services->GetDictionaryWithoutPathExpansion(*iter, &one_service)) { | |
| 1801 *error = ASCIIToUTF16(errors::kInvalidIntent); | |
| 1802 return false; | |
| 1803 } | |
| 1804 service.action = UTF8ToUTF16(*iter); | |
| 1805 | |
| 1806 ListValue* mime_types = NULL; | |
| 1807 if (!one_service->HasKey(keys::kIntentType) || | |
| 1808 !one_service->GetList(keys::kIntentType, &mime_types) || | |
| 1809 mime_types->GetSize() == 0) { | |
| 1810 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1811 errors::kInvalidIntentType, *iter); | |
| 1812 return false; | |
| 1813 } | |
| 1814 | |
| 1815 if (one_service->HasKey(keys::kIntentPath)) { | |
| 1816 if (!one_service->GetString(keys::kIntentPath, &value)) { | |
| 1817 *error = ASCIIToUTF16(errors::kInvalidIntentPath); | |
| 1818 return false; | |
| 1819 } | |
| 1820 if (is_hosted_app()) { | |
| 1821 // Hosted apps require an absolute URL for intents. | |
| 1822 GURL service_url(value); | |
| 1823 if (!service_url.is_valid() || | |
| 1824 !(web_extent().MatchesURL(service_url))) { | |
| 1825 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1826 errors::kInvalidIntentPageInHostedApp, *iter); | |
| 1827 return false; | |
| 1828 } | |
| 1829 service.service_url = service_url; | |
| 1830 } else { | |
| 1831 // We do not allow absolute intent URLs in non-hosted apps. | |
| 1832 if (GURL(value).is_valid()) { | |
| 1833 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1834 errors::kCannotAccessPage, value.c_str()); | |
| 1835 return false; | |
| 1836 } | |
| 1837 service.service_url = GetResourceURL(value); | |
| 1838 } | |
| 1839 } | |
| 1840 | |
| 1841 if (one_service->HasKey(keys::kIntentTitle) && | |
| 1842 !one_service->GetString(keys::kIntentTitle, &service.title)) { | |
| 1843 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | |
| 1844 return false; | |
| 1845 } | |
| 1846 | |
| 1847 if (one_service->HasKey(keys::kIntentDisposition)) { | |
| 1848 if (!one_service->GetString(keys::kIntentDisposition, &value) || | |
| 1849 (value != values::kIntentDispositionWindow && | |
| 1850 value != values::kIntentDispositionInline)) { | |
| 1851 *error = ASCIIToUTF16(errors::kInvalidIntentDisposition); | |
| 1852 return false; | |
| 1853 } | |
| 1854 if (value == values::kIntentDispositionInline) { | |
| 1855 service.disposition = | |
| 1856 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; | |
| 1857 } else { | |
| 1858 service.disposition = | |
| 1859 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW; | |
| 1860 } | |
| 1861 } | |
| 1862 | |
| 1863 for (size_t i = 0; i < mime_types->GetSize(); ++i) { | |
| 1864 if (!mime_types->GetString(i, &service.type)) { | |
| 1865 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1866 errors::kInvalidIntentTypeElement, *iter, | |
| 1867 std::string(base::IntToString(i))); | |
| 1868 return false; | |
| 1869 } | |
| 1870 intents_services_.push_back(service); | |
| 1871 } | |
| 1872 } | |
| 1873 return true; | |
| 1874 } | |
| 1875 | |
| 1876 bool Extension::LoadExtensionFeatures( | |
| 1877 const ExtensionAPIPermissionSet& api_permissions, | |
| 1878 string16* error) { | |
| 1879 if (manifest_->HasKey(keys::kConvertedFromUserScript)) | |
| 1880 manifest_->GetBoolean(keys::kConvertedFromUserScript, | |
| 1881 &converted_from_user_script_); | |
| 1882 | |
| 1883 if (!LoadDevToolsPage(error) || | |
| 1884 !LoadInputComponents(api_permissions, error) || | |
| 1885 !LoadContentScripts(error) || | |
| 1886 !LoadPageAction(error) || | |
| 1887 !LoadBrowserAction(error) || | |
| 1888 !LoadFileBrowserHandlers(error) || | |
| 1889 !LoadChromeURLOverrides(error) || | |
| 1890 !LoadOmnibox(error) || | |
| 1891 !LoadTextToSpeechVoices(error) || | |
| 1892 !LoadIncognitoMode(error) || | |
| 1893 !LoadContentSecurityPolicy(error)) | |
| 1894 return false; | |
| 1895 | |
| 1896 return true; | |
| 1897 } | |
| 1898 | |
| 1899 bool Extension::LoadDevToolsPage(string16* error) { | |
| 1900 if (!manifest_->HasKey(keys::kDevToolsPage)) | |
| 1901 return true; | |
| 1902 std::string devtools_str; | |
| 1903 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) { | |
| 1904 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage); | |
| 1905 return false; | |
| 1906 } | |
| 1907 devtools_url_ = GetResourceURL(devtools_str); | |
| 1908 return true; | |
| 1909 } | |
| 1910 | |
| 1911 bool Extension::LoadInputComponents( | |
| 1912 const ExtensionAPIPermissionSet& api_permissions, | |
| 1913 string16* error) { | |
| 1914 if (!manifest_->HasKey(keys::kInputComponents)) | |
| 1915 return true; | |
| 1916 ListValue* list_value = NULL; | |
| 1917 if (!manifest_->GetList(keys::kInputComponents, &list_value)) { | |
| 1918 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 1919 return false; | |
| 1920 } | |
| 1921 | |
| 1922 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 1923 DictionaryValue* module_value = NULL; | |
| 1924 std::string name_str; | |
| 1925 InputComponentType type; | |
| 1926 std::string id_str; | |
| 1927 std::string description_str; | |
| 1928 std::string language_str; | |
| 1929 std::set<std::string> layouts; | |
| 1930 std::string shortcut_keycode_str; | |
| 1931 bool shortcut_alt = false; | |
| 1932 bool shortcut_ctrl = false; | |
| 1933 bool shortcut_shift = false; | |
| 1934 | |
| 1935 if (!list_value->GetDictionary(i, &module_value)) { | |
| 1936 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 1937 return false; | |
| 1938 } | |
| 1939 | |
| 1940 // Get input_components[i].name. | |
| 1941 if (!module_value->GetString(keys::kName, &name_str)) { | |
| 1942 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1943 errors::kInvalidInputComponentName, base::IntToString(i)); | |
| 1944 return false; | |
| 1945 } | |
| 1946 | |
| 1947 // Get input_components[i].type. | |
| 1948 std::string type_str; | |
| 1949 if (module_value->GetString(keys::kType, &type_str)) { | |
| 1950 if (type_str == "ime") { | |
| 1951 type = INPUT_COMPONENT_TYPE_IME; | |
| 1952 } else if (type_str == "virtual_keyboard") { | |
| 1953 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { | |
| 1954 // Virtual Keyboards require the experimental flag. | |
| 1955 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1956 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 1957 return false; | |
| 1958 } | |
| 1959 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD; | |
| 1960 } else { | |
| 1961 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1962 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 1963 return false; | |
| 1964 } | |
| 1965 } else { | |
| 1966 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1967 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 1968 return false; | |
| 1969 } | |
| 1970 | |
| 1971 // Get input_components[i].id. | |
| 1972 if (!module_value->GetString(keys::kId, &id_str)) { | |
| 1973 id_str = ""; | |
| 1974 } | |
| 1975 | |
| 1976 // Get input_components[i].description. | |
| 1977 if (!module_value->GetString(keys::kDescription, &description_str)) { | |
| 1978 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1979 errors::kInvalidInputComponentDescription, base::IntToString(i)); | |
| 1980 return false; | |
| 1981 } | |
| 1982 // Get input_components[i].language. | |
| 1983 if (!module_value->GetString(keys::kLanguage, &language_str)) { | |
| 1984 language_str = ""; | |
| 1985 } | |
| 1986 | |
| 1987 // Get input_components[i].layouts. | |
| 1988 ListValue* layouts_value = NULL; | |
| 1989 if (!module_value->GetList(keys::kLayouts, &layouts_value)) { | |
| 1990 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts); | |
| 1991 return false; | |
| 1992 } | |
| 1993 | |
| 1994 for (size_t j = 0; j < layouts_value->GetSize(); ++j) { | |
| 1995 std::string layout_name_str; | |
| 1996 if (!layouts_value->GetString(j, &layout_name_str)) { | |
| 1997 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1998 errors::kInvalidInputComponentLayoutName, base::IntToString(i), | |
| 1999 base::IntToString(j)); | |
| 2000 return false; | |
| 2001 } | |
| 2002 layouts.insert(layout_name_str); | |
| 2003 } | |
| 2004 | |
| 2005 if (module_value->HasKey(keys::kShortcutKey)) { | |
| 2006 DictionaryValue* shortcut_value = NULL; | |
| 2007 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) { | |
| 2008 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2009 errors::kInvalidInputComponentShortcutKey, base::IntToString(i)); | |
| 2010 return false; | |
| 2011 } | |
| 2012 | |
| 2013 // Get input_components[i].shortcut_keycode. | |
| 2014 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) { | |
| 2015 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2016 errors::kInvalidInputComponentShortcutKeycode, | |
| 2017 base::IntToString(i)); | |
| 2018 return false; | |
| 2019 } | |
| 2020 | |
| 2021 // Get input_components[i].shortcut_alt. | |
| 2022 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) { | |
| 2023 shortcut_alt = false; | |
| 2024 } | |
| 2025 | |
| 2026 // Get input_components[i].shortcut_ctrl. | |
| 2027 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) { | |
| 2028 shortcut_ctrl = false; | |
| 2029 } | |
| 2030 | |
| 2031 // Get input_components[i].shortcut_shift. | |
| 2032 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) { | |
| 2033 shortcut_shift = false; | |
| 2034 } | |
| 2035 } | |
| 2036 | |
| 2037 input_components_.push_back(InputComponentInfo()); | |
| 2038 input_components_.back().name = name_str; | |
| 2039 input_components_.back().type = type; | |
| 2040 input_components_.back().id = id_str; | |
| 2041 input_components_.back().description = description_str; | |
| 2042 input_components_.back().language = language_str; | |
| 2043 input_components_.back().layouts.insert(layouts.begin(), layouts.end()); | |
| 2044 input_components_.back().shortcut_keycode = shortcut_keycode_str; | |
| 2045 input_components_.back().shortcut_alt = shortcut_alt; | |
| 2046 input_components_.back().shortcut_ctrl = shortcut_ctrl; | |
| 2047 input_components_.back().shortcut_shift = shortcut_shift; | |
| 2048 } | |
| 2049 | |
| 2050 return true; | |
| 2051 } | |
| 2052 | |
| 2053 bool Extension::LoadContentScripts(string16* error) { | |
| 2054 if (!manifest_->HasKey(keys::kContentScripts)) | |
| 2055 return true; | |
| 2056 ListValue* list_value; | |
| 2057 if (!manifest_->GetList(keys::kContentScripts, &list_value)) { | |
| 2058 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList); | |
| 2059 return false; | |
| 2060 } | |
| 2061 | |
| 2062 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2063 DictionaryValue* content_script = NULL; | |
| 2064 if (!list_value->GetDictionary(i, &content_script)) { | |
| 2065 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2066 errors::kInvalidContentScript, base::IntToString(i)); | |
| 2067 return false; | |
| 2068 } | |
| 2069 | |
| 2070 UserScript script; | |
| 2071 if (!LoadUserScriptHelper(content_script, i, error, &script)) | |
| 2072 return false; // Failed to parse script context definition. | |
| 2073 script.set_extension_id(id()); | |
| 2074 if (converted_from_user_script_) { | |
| 2075 script.set_emulate_greasemonkey(true); | |
| 2076 script.set_match_all_frames(true); // Greasemonkey matches all frames. | |
| 2077 } | |
| 2078 content_scripts_.push_back(script); | |
| 2079 } | |
| 2080 return true; | |
| 2081 } | |
| 2082 | |
| 2083 bool Extension::LoadPageAction(string16* error) { | |
| 2084 DictionaryValue* page_action_value = NULL; | |
| 2085 | |
| 2086 if (manifest_->HasKey(keys::kPageActions)) { | |
| 2087 ListValue* list_value = NULL; | |
| 2088 if (!manifest_->GetList(keys::kPageActions, &list_value)) { | |
| 2089 *error = ASCIIToUTF16(errors::kInvalidPageActionsList); | |
| 2090 return false; | |
| 2091 } | |
| 2092 | |
| 2093 size_t list_value_length = list_value->GetSize(); | |
| 2094 | |
| 2095 if (list_value_length == 0u) { | |
| 2096 // A list with zero items is allowed, and is equivalent to not having | |
| 2097 // a page_actions key in the manifest. Don't set |page_action_value|. | |
| 2098 } else if (list_value_length == 1u) { | |
| 2099 if (!list_value->GetDictionary(0, &page_action_value)) { | |
| 2100 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2101 return false; | |
| 2102 } | |
| 2103 } else { // list_value_length > 1u. | |
| 2104 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize); | |
| 2105 return false; | |
| 2106 } | |
| 2107 } else if (manifest_->HasKey(keys::kPageAction)) { | |
| 2108 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { | |
| 2109 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2110 return false; | |
| 2111 } | |
| 2112 } | |
| 2113 | |
| 2114 // If page_action_value is not NULL, then there was a valid page action. | |
| 2115 if (page_action_value) { | |
| 2116 page_action_.reset( | |
| 2117 LoadExtensionActionHelper(page_action_value, error)); | |
| 2118 if (!page_action_.get()) | |
| 2119 return false; // Failed to parse page action definition. | |
| 2120 } | |
| 2121 | |
| 2122 return true; | |
| 2123 } | |
| 2124 | |
| 2125 bool Extension::LoadBrowserAction(string16* error) { | |
| 2126 if (!manifest_->HasKey(keys::kBrowserAction)) | |
| 2127 return true; | |
| 2128 DictionaryValue* browser_action_value = NULL; | |
| 2129 if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) { | |
| 2130 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); | |
| 2131 return false; | |
| 2132 } | |
| 2133 | |
| 2134 browser_action_.reset( | |
| 2135 LoadExtensionActionHelper(browser_action_value, error)); | |
| 2136 if (!browser_action_.get()) | |
| 2137 return false; // Failed to parse browser action definition. | |
| 2138 return true; | |
| 2139 } | |
| 2140 | |
| 2141 bool Extension::LoadFileBrowserHandlers(string16* error) { | |
| 2142 if (!manifest_->HasKey(keys::kFileBrowserHandlers)) | |
| 2143 return true; | |
| 2144 ListValue* file_browser_handlers_value = NULL; | |
| 2145 if (!manifest_->GetList(keys::kFileBrowserHandlers, | |
| 2146 &file_browser_handlers_value)) { | |
| 2147 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2148 return false; | |
| 2149 } | |
| 2150 file_browser_handlers_.reset( | |
| 2151 LoadFileBrowserHandlersHelper(file_browser_handlers_value, error)); | |
| 2152 if (!file_browser_handlers_.get()) | |
| 2153 return false; // Failed to parse file browser actions definition. | |
| 2154 return true; | |
| 2155 } | |
| 2156 | |
| 2157 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlersHelper( | |
| 2158 const ListValue* extension_actions, string16* error) { | |
| 2159 scoped_ptr<FileBrowserHandlerList> result( | |
| 2160 new FileBrowserHandlerList()); | |
| 2161 for (ListValue::const_iterator iter = extension_actions->begin(); | |
| 2162 iter != extension_actions->end(); | |
| 2163 ++iter) { | |
| 2164 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) { | |
| 2165 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2166 return NULL; | |
| 2167 } | |
| 2168 scoped_ptr<FileBrowserHandler> action( | |
| 2169 LoadFileBrowserHandler( | |
| 2170 reinterpret_cast<DictionaryValue*>(*iter), error)); | |
| 2171 if (!action.get()) | |
| 2172 return NULL; // Failed to parse file browser action definition. | |
| 2173 result->push_back(linked_ptr<FileBrowserHandler>(action.release())); | |
| 2174 } | |
| 2175 return result.release(); | |
| 2176 } | |
| 2177 | |
| 2178 FileBrowserHandler* Extension::LoadFileBrowserHandler( | |
| 2179 const DictionaryValue* file_browser_handler, string16* error) { | |
| 2180 scoped_ptr<FileBrowserHandler> result( | |
| 2181 new FileBrowserHandler()); | |
| 2182 result->set_extension_id(id()); | |
| 2183 | |
| 2184 std::string id; | |
| 2185 // Read the file action |id| (mandatory). | |
| 2186 if (!file_browser_handler->HasKey(keys::kPageActionId) || | |
| 2187 !file_browser_handler->GetString(keys::kPageActionId, &id)) { | |
| 2188 *error = ASCIIToUTF16(errors::kInvalidPageActionId); | |
| 2189 return NULL; | |
| 2190 } | |
| 2191 result->set_id(id); | |
| 2192 | |
| 2193 // Read the page action title from |default_title| (mandatory). | |
| 2194 std::string title; | |
| 2195 if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) || | |
| 2196 !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) { | |
| 2197 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); | |
| 2198 return NULL; | |
| 2199 } | |
| 2200 result->set_title(title); | |
| 2201 | |
| 2202 // Initialize file filters (mandatory). | |
| 2203 ListValue* list_value = NULL; | |
| 2204 if (!file_browser_handler->HasKey(keys::kFileFilters) || | |
| 2205 !file_browser_handler->GetList(keys::kFileFilters, &list_value) || | |
| 2206 list_value->empty()) { | |
| 2207 *error = ASCIIToUTF16(errors::kInvalidFileFiltersList); | |
| 2208 return NULL; | |
| 2209 } | |
| 2210 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2211 std::string filter; | |
| 2212 if (!list_value->GetString(i, &filter)) { | |
| 2213 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2214 errors::kInvalidFileFilterValue, base::IntToString(i)); | |
| 2215 return NULL; | |
| 2216 } | |
| 2217 StringToLowerASCII(&filter); | |
| 2218 URLPattern pattern(URLPattern::SCHEME_FILESYSTEM); | |
| 2219 if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) { | |
| 2220 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2221 errors::kInvalidURLPatternError, filter); | |
| 2222 return NULL; | |
| 2223 } | |
| 2224 std::string path = pattern.path(); | |
| 2225 bool allowed = path == "*" || path == "*.*" || | |
| 2226 (path.compare(0, 2, "*.") == 0 && | |
| 2227 path.find_first_of('*', 2) == std::string::npos); | |
| 2228 if (!allowed) { | |
| 2229 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2230 errors::kInvalidURLPatternError, filter); | |
| 2231 return NULL; | |
| 2232 } | |
| 2233 result->AddPattern(pattern); | |
| 2234 } | |
| 2235 | |
| 2236 std::string default_icon; | |
| 2237 // Read the file browser action |default_icon| (optional). | |
| 2238 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { | |
| 2239 if (!file_browser_handler->GetString( | |
| 2240 keys::kPageActionDefaultIcon, &default_icon) || | |
| 2241 default_icon.empty()) { | |
| 2242 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | |
| 2243 return NULL; | |
| 2244 } | |
| 2245 result->set_icon_path(default_icon); | |
| 2246 } | |
| 2247 | |
| 2248 return result.release(); | |
| 2249 } | |
| 2250 | |
| 2251 bool Extension::LoadChromeURLOverrides(string16* error) { | |
| 2252 if (!manifest_->HasKey(keys::kChromeURLOverrides)) | |
| 2253 return true; | |
| 2254 DictionaryValue* overrides = NULL; | |
| 2255 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) { | |
| 2256 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2257 return false; | |
| 2258 } | |
| 2259 | |
| 2260 // Validate that the overrides are all strings | |
| 2261 for (DictionaryValue::key_iterator iter = overrides->begin_keys(); | |
| 2262 iter != overrides->end_keys(); ++iter) { | |
| 2263 std::string page = *iter; | |
| 2264 std::string val; | |
| 2265 // Restrict override pages to a list of supported URLs. | |
| 2266 if ((page != chrome::kChromeUINewTabHost && | |
| 2267 #if defined(USE_VIRTUAL_KEYBOARD) | |
| 2268 page != chrome::kChromeUIKeyboardHost && | |
| 2269 #endif | |
| 2270 #if defined(OS_CHROMEOS) | |
| 2271 page != chrome::kChromeUIActivationMessageHost && | |
| 2272 #endif | |
| 2273 page != chrome::kChromeUIBookmarksHost && | |
| 2274 page != chrome::kChromeUIHistoryHost | |
| 2275 #if defined(FILE_MANAGER_EXTENSION) | |
| 2276 && | |
| 2277 !(location() == COMPONENT && | |
| 2278 page == chrome::kChromeUIFileManagerHost) | |
| 2279 #endif | |
| 2280 ) || | |
| 2281 !overrides->GetStringWithoutPathExpansion(*iter, &val)) { | |
| 2282 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2283 return false; | |
| 2284 } | |
| 2285 // Replace the entry with a fully qualified chrome-extension:// URL. | |
| 2286 chrome_url_overrides_[page] = GetResourceURL(val); | |
| 2287 } | |
| 2288 | |
| 2289 // An extension may override at most one page. | |
| 2290 if (overrides->size() > 1) { | |
| 2291 *error = ASCIIToUTF16(errors::kMultipleOverrides); | |
| 2292 return false; | |
| 2293 } | |
| 2294 | |
| 2295 return true; | |
| 2296 } | |
| 2297 | |
| 2298 bool Extension::LoadOmnibox(string16* error) { | |
| 2299 if (!manifest_->HasKey(keys::kOmnibox)) | |
| 2300 return true; | |
| 2301 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || | |
| 2302 omnibox_keyword_.empty()) { | |
|
Yoyo Zhou
2012/03/02 20:20:07
indent -1
The style guide doesn't treat leading un
Devlin
2012/03/07 04:18:54
Done.
| |
| 2303 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword); | |
| 2304 return false; | |
| 2305 } | |
| 2306 return true; | |
| 2307 } | |
| 2308 | |
| 2309 bool Extension::LoadTextToSpeechVoices(string16* error) { | |
| 2310 if (!manifest_->HasKey(keys::kTtsEngine)) | |
| 2311 return true; | |
| 2312 DictionaryValue* tts_dict = NULL; | |
| 2313 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) { | |
| 2314 *error = ASCIIToUTF16(errors::kInvalidTts); | |
| 2315 return false; | |
| 2316 } | |
| 2317 | |
| 2318 if (tts_dict->HasKey(keys::kTtsVoices)) { | |
| 2319 ListValue* tts_voices = NULL; | |
| 2320 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) { | |
| 2321 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2322 return false; | |
| 2323 } | |
| 2324 | |
| 2325 for (size_t i = 0; i < tts_voices->GetSize(); i++) { | |
| 2326 DictionaryValue* one_tts_voice = NULL; | |
| 2327 if (!tts_voices->GetDictionary(i, &one_tts_voice)) { | |
| 2328 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2329 return false; | |
| 2330 } | |
| 2331 | |
| 2332 TtsVoice voice_data; | |
| 2333 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) { | |
| 2334 if (!one_tts_voice->GetString( | |
| 2335 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) { | |
| 2336 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName); | |
| 2337 return false; | |
| 2338 } | |
| 2339 } | |
| 2340 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) { | |
| 2341 if (!one_tts_voice->GetString( | |
| 2342 keys::kTtsVoicesLang, &voice_data.lang) || | |
| 2343 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) { | |
| 2344 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang); | |
| 2345 return false; | |
| 2346 } | |
| 2347 } | |
| 2348 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) { | |
| 2349 if (!one_tts_voice->GetString( | |
| 2350 keys::kTtsVoicesGender, &voice_data.gender) || | |
| 2351 (voice_data.gender != keys::kTtsGenderMale && | |
| 2352 voice_data.gender != keys::kTtsGenderFemale)) { | |
| 2353 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender); | |
| 2354 return false; | |
| 2355 } | |
| 2356 } | |
| 2357 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) { | |
| 2358 ListValue* event_types_list; | |
| 2359 if (!one_tts_voice->GetList( | |
| 2360 keys::kTtsVoicesEventTypes, &event_types_list)) { | |
| 2361 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2362 return false; | |
| 2363 } | |
| 2364 for (size_t i = 0; i < event_types_list->GetSize(); i++) { | |
| 2365 std::string event_type; | |
| 2366 if (!event_types_list->GetString(i, &event_type)) { | |
| 2367 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2368 return false; | |
| 2369 } | |
| 2370 if (event_type != keys::kTtsVoicesEventTypeEnd && | |
| 2371 event_type != keys::kTtsVoicesEventTypeError && | |
| 2372 event_type != keys::kTtsVoicesEventTypeMarker && | |
| 2373 event_type != keys::kTtsVoicesEventTypeSentence && | |
| 2374 event_type != keys::kTtsVoicesEventTypeStart && | |
| 2375 event_type != keys::kTtsVoicesEventTypeWord) { | |
| 2376 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2377 return false; | |
| 2378 } | |
| 2379 if (voice_data.event_types.find(event_type) != | |
| 2380 voice_data.event_types.end()) { | |
| 2381 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2382 return false; | |
| 2383 } | |
| 2384 voice_data.event_types.insert(event_type); | |
| 2385 } | |
| 2386 } | |
| 2387 | |
| 2388 tts_voices_.push_back(voice_data); | |
| 2389 } | |
| 2390 } | |
| 2391 return true; | |
| 2392 } | |
| 2393 | |
| 2394 bool Extension::LoadIncognitoMode(string16* error) { | |
| 2395 // Apps default to split mode, extensions default to spanning. | |
| 2396 incognito_split_mode_ = is_app(); | |
| 2397 if (!manifest_->HasKey(keys::kIncognito)) | |
| 2398 return true; | |
| 2399 std::string value; | |
| 2400 if (!manifest_->GetString(keys::kIncognito, &value)) { | |
| 2401 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2402 return false; | |
| 2403 } | |
| 2404 if (value == values::kIncognitoSpanning) { | |
| 2405 incognito_split_mode_ = false; | |
| 2406 } else if (value == values::kIncognitoSplit) { | |
| 2407 incognito_split_mode_ = true; | |
| 2408 } else { | |
| 2409 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2410 return false; | |
| 2411 } | |
| 2412 return true; | |
| 2413 } | |
| 2414 | |
| 2415 bool Extension::LoadContentSecurityPolicy(string16* error) { | |
| 2416 if (manifest_->HasKey(keys::kContentSecurityPolicy)) { | |
| 2417 std::string content_security_policy; | |
| 2418 if (!manifest_->GetString(keys::kContentSecurityPolicy, | |
| 2419 &content_security_policy)) { | |
| 2420 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2421 return false; | |
| 2422 } | |
| 2423 if (!ContentSecurityPolicyIsLegal(content_security_policy)) { | |
| 2424 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2425 return false; | |
| 2426 } | |
| 2427 if (manifest_version_ >= 2 && | |
| 2428 !ContentSecurityPolicyIsSecure(content_security_policy)) { | |
| 2429 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2430 return false; | |
| 2431 } | |
| 2432 | |
| 2433 content_security_policy_ = content_security_policy; | |
| 2434 } else if (manifest_version_ >= 2) { | |
| 2435 // Manifest version 2 introduced a default Content-Security-Policy. | |
| 2436 // TODO(abarth): Should we continue to let extensions override the | |
| 2437 // default Content-Security-Policy? | |
| 2438 content_security_policy_ = kDefaultContentSecurityPolicy; | |
| 2439 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_)); | |
| 2440 } | |
| 2441 return true; | |
| 2442 } | |
| 2443 | |
| 2444 bool Extension::LoadAppIsolation(string16* error) { | |
| 2445 Value* temp = NULL; | |
| 2446 if (!manifest_->Get(keys::kIsolation, &temp)) | |
| 2447 return true; | |
| 2448 | |
| 2449 if (temp->GetType() != Value::TYPE_LIST) { | |
| 2450 *error = ASCIIToUTF16(errors::kInvalidIsolation); | |
| 2451 return false; | |
| 2452 } | |
| 2453 | |
| 2454 ListValue* isolation_list = static_cast<ListValue*>(temp); | |
| 2455 for (size_t i = 0; i < isolation_list->GetSize(); ++i) { | |
| 2456 std::string isolation_string; | |
| 2457 if (!isolation_list->GetString(i, &isolation_string)) { | |
| 2458 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2459 errors::kInvalidIsolationValue, | |
| 2460 base::UintToString(i)); | |
| 2461 return false; | |
| 2462 } | |
| 2463 | |
| 2464 // Check for isolated storage. | |
| 2465 if (isolation_string == values::kIsolatedStorage) { | |
| 2466 is_storage_isolated_ = true; | |
| 2467 } else { | |
| 2468 DLOG(WARNING) << "Did not recognize isolation type: " | |
| 2469 << isolation_string; | |
| 2470 } | |
| 2471 } | |
| 2472 return true; | |
| 2473 } | |
| 2474 | |
| 2475 bool Extension::LoadThemeFeatures(string16* error) { | |
| 2476 if (!manifest_->HasKey(keys::kTheme)) | |
| 2477 return true; | |
| 2478 DictionaryValue* theme_value = NULL; | |
| 2479 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { | |
| 2480 *error = ASCIIToUTF16(errors::kInvalidTheme); | |
| 2481 return false; | |
| 2482 } | |
| 2483 if (!LoadThemeImages(theme_value, error)) | |
| 2484 return false; | |
| 2485 if (!LoadThemeColors(theme_value, error)) | |
| 2486 return false; | |
| 2487 if (!LoadThemeTints(theme_value, error)) | |
| 2488 return false; | |
| 2489 if (!LoadThemeDisplayProperties(theme_value, error)) | |
| 2490 return false; | |
| 2491 | |
| 2492 return true; | |
| 2493 } | |
| 2494 | |
| 2495 bool Extension::LoadThemeImages(const DictionaryValue* theme_value, | |
| 2496 string16* error) { | |
| 2497 DictionaryValue* images_value = NULL; | |
| 2498 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { | |
| 2499 // Validate that the images are all strings | |
| 2500 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); | |
| 2501 iter != images_value->end_keys(); ++iter) { | |
| 2502 std::string val; | |
| 2503 if (!images_value->GetString(*iter, &val)) { | |
| 2504 *error = ASCIIToUTF16(errors::kInvalidThemeImages); | |
| 2505 return false; | |
| 2506 } | |
| 2507 } | |
| 2508 theme_images_.reset(images_value->DeepCopy()); | |
| 2509 } | |
| 2510 return true; | |
| 2511 } | |
| 2512 | |
| 2513 bool Extension::LoadThemeColors(const DictionaryValue* theme_value, | |
| 2514 string16* error) { | |
| 2515 DictionaryValue* colors_value = NULL; | |
| 2516 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { | |
| 2517 // Validate that the colors are RGB or RGBA lists | |
| 2518 for (DictionaryValue::key_iterator iter = colors_value->begin_keys(); | |
| 2519 iter != colors_value->end_keys(); ++iter) { | |
| 2520 ListValue* color_list = NULL; | |
| 2521 double alpha = 0.0; | |
| 2522 int color = 0; | |
| 2523 // The color must be a list | |
| 2524 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) || | |
| 2525 // And either 3 items (RGB) or 4 (RGBA) | |
| 2526 ((color_list->GetSize() != 3) && | |
| 2527 ((color_list->GetSize() != 4) || | |
| 2528 // For RGBA, the fourth item must be a real or int alpha value. | |
| 2529 // Note that GetDouble() can get an integer value. | |
| 2530 !color_list->GetDouble(3, &alpha))) || | |
| 2531 // For both RGB and RGBA, the first three items must be ints (R,G,B) | |
| 2532 !color_list->GetInteger(0, &color) || | |
| 2533 !color_list->GetInteger(1, &color) || | |
| 2534 !color_list->GetInteger(2, &color)) { | |
| 2535 *error = ASCIIToUTF16(errors::kInvalidThemeColors); | |
| 2536 return false; | |
| 2537 } | |
| 2538 } | |
| 2539 theme_colors_.reset(colors_value->DeepCopy()); | |
| 2540 } | |
| 2541 return true; | |
| 2542 } | |
| 2543 | |
| 2544 bool Extension::LoadThemeTints(const DictionaryValue* theme_value, | |
| 2545 string16* error) { | |
| 2546 DictionaryValue* tints_value = NULL; | |
| 2547 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) { | |
| 2548 // Validate that the tints are all reals. | |
| 2549 for (DictionaryValue::key_iterator iter = tints_value->begin_keys(); | |
| 2550 iter != tints_value->end_keys(); ++iter) { | |
| 2551 ListValue* tint_list = NULL; | |
| 2552 double v = 0.0; | |
| 2553 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) || | |
| 2554 tint_list->GetSize() != 3 || | |
| 2555 !tint_list->GetDouble(0, &v) || | |
| 2556 !tint_list->GetDouble(1, &v) || | |
| 2557 !tint_list->GetDouble(2, &v)) { | |
| 2558 *error = ASCIIToUTF16(errors::kInvalidThemeTints); | |
| 2559 return false; | |
| 2560 } | |
| 2561 } | |
| 2562 theme_tints_.reset(tints_value->DeepCopy()); | |
| 2563 } | |
| 2564 return true; | |
| 2565 } | |
| 2566 | |
| 2567 bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value, | |
| 2568 string16* error) { | |
| 2569 DictionaryValue* display_properties_value = NULL; | |
| 2570 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, | |
| 2571 &display_properties_value)) { | |
| 2572 theme_display_properties_.reset( | |
| 2573 display_properties_value->DeepCopy()); | |
| 2574 } | |
| 2575 return true; | |
| 2576 } | |
| 2577 | |
| 1518 // static | 2578 // static |
| 1519 bool Extension::IsTrustedId(const std::string& id) { | 2579 bool Extension::IsTrustedId(const std::string& id) { |
| 1520 // See http://b/4946060 for more details. | 2580 // See http://b/4946060 for more details. |
| 1521 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); | 2581 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); |
| 1522 } | 2582 } |
| 1523 | 2583 |
| 1524 Extension::Extension(const FilePath& path, | 2584 Extension::Extension(const FilePath& path, |
| 1525 scoped_ptr<extensions::Manifest> manifest) | 2585 scoped_ptr<extensions::Manifest> manifest) |
| 1526 : manifest_version_(0), | 2586 : manifest_version_(0), |
| 1527 incognito_split_mode_(false), | 2587 incognito_split_mode_(false), |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1690 const SkBitmap& Extension::GetDefaultIcon(bool is_app) { | 2750 const SkBitmap& Extension::GetDefaultIcon(bool is_app) { |
| 1691 if (is_app) { | 2751 if (is_app) { |
| 1692 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | 2752 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 1693 IDR_APP_DEFAULT_ICON); | 2753 IDR_APP_DEFAULT_ICON); |
| 1694 } else { | 2754 } else { |
| 1695 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( | 2755 return *ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 1696 IDR_EXTENSION_DEFAULT_ICON); | 2756 IDR_EXTENSION_DEFAULT_ICON); |
| 1697 } | 2757 } |
| 1698 } | 2758 } |
| 1699 | 2759 |
| 2760 // static | |
| 1700 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { | 2761 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { |
| 1701 return GURL(std::string(chrome::kExtensionScheme) + | 2762 return GURL(std::string(chrome::kExtensionScheme) + |
| 1702 chrome::kStandardSchemeSeparator + extension_id + "/"); | 2763 chrome::kStandardSchemeSeparator + extension_id + "/"); |
| 1703 } | 2764 } |
| 1704 | 2765 |
| 1705 bool Extension::LoadManifestVersion(string16* error) { | |
| 1706 // Get the original value out of the dictionary so that we can validate it | |
| 1707 // more strictly. | |
| 1708 if (manifest_->value()->HasKey(keys::kManifestVersion)) { | |
| 1709 int manifest_version = 1; | |
| 1710 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) || | |
| 1711 manifest_version < 1) { | |
| 1712 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1713 return false; | |
| 1714 } | |
| 1715 } | |
| 1716 | |
| 1717 manifest_version_ = manifest_->GetManifestVersion(); | |
| 1718 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION && | |
| 1719 manifest_version_ < kModernManifestVersion && | |
| 1720 !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1721 switches::kAllowLegacyExtensionManifests)) { | |
| 1722 *error = ASCIIToUTF16(errors::kInvalidManifestVersion); | |
| 1723 return false; | |
| 1724 } | |
| 1725 | |
| 1726 return true; | |
| 1727 } | |
| 1728 | |
| 1729 // static | |
| 1730 bool Extension::InitExtensionID(extensions::Manifest* manifest, | |
| 1731 const FilePath& path, | |
| 1732 const std::string& explicit_id, | |
| 1733 int creation_flags, | |
| 1734 string16* error) { | |
| 1735 if (!explicit_id.empty()) { | |
| 1736 manifest->set_extension_id(explicit_id); | |
| 1737 return true; | |
| 1738 } | |
| 1739 | |
| 1740 if (manifest->HasKey(keys::kPublicKey)) { | |
| 1741 std::string public_key; | |
| 1742 std::string public_key_bytes; | |
| 1743 std::string extension_id; | |
| 1744 if (!manifest->GetString(keys::kPublicKey, &public_key) || | |
| 1745 !ParsePEMKeyBytes(public_key, &public_key_bytes) || | |
| 1746 !GenerateId(public_key_bytes, &extension_id)) { | |
| 1747 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 1748 return false; | |
| 1749 } | |
| 1750 manifest->set_extension_id(extension_id); | |
| 1751 return true; | |
| 1752 } | |
| 1753 | |
| 1754 if (creation_flags & REQUIRE_KEY) { | |
| 1755 *error = ASCIIToUTF16(errors::kInvalidKey); | |
| 1756 return false; | |
| 1757 } else { | |
| 1758 // If there is a path, we generate the ID from it. This is useful for | |
| 1759 // development mode, because it keeps the ID stable across restarts and | |
| 1760 // reloading the extension. | |
| 1761 std::string extension_id = GenerateIdForPath(path); | |
| 1762 if (extension_id.empty()) { | |
| 1763 NOTREACHED() << "Could not create ID from path."; | |
| 1764 return false; | |
| 1765 } | |
| 1766 manifest->set_extension_id(extension_id); | |
| 1767 return true; | |
| 1768 } | |
| 1769 } | |
| 1770 | |
| 1771 bool Extension::InitFromValue(int flags, string16* error) { | 2766 bool Extension::InitFromValue(int flags, string16* error) { |
| 1772 DCHECK(error); | 2767 DCHECK(error); |
| 1773 | 2768 |
| 1774 base::AutoLock auto_lock(runtime_data_lock_); | 2769 base::AutoLock auto_lock(runtime_data_lock_); |
| 1775 | 2770 |
| 1776 // Initialize permissions with an empty, default permission set. | 2771 // Initialize permissions with an empty, default permission set. |
| 1777 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); | 2772 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); |
| 1778 optional_permission_set_ = new ExtensionPermissionSet(); | 2773 optional_permission_set_ = new ExtensionPermissionSet(); |
| 1779 required_permission_set_ = new ExtensionPermissionSet(); | 2774 required_permission_set_ = new ExtensionPermissionSet(); |
| 1780 | 2775 |
| 1781 creation_flags_ = flags; | 2776 creation_flags_ = flags; |
| 1782 | 2777 |
| 1783 if (!LoadManifestVersion(error)) | 2778 // Validate minimum Chrome version. We don't need to store this, since the |
| 2779 // extension is not valid if it is incorrect | |
| 2780 if (!CheckMinimumChromeVersion(error)) | |
| 2781 return false; | |
| 2782 | |
| 2783 // Loads the required fields for an extension; this must be done first. | |
|
Yoyo Zhou
2012/03/02 20:20:07
There seems to be no need to actually load these t
Devlin
2012/03/07 04:18:54
Done.
| |
| 2784 if (!LoadRequiredFeatures(error)) | |
| 1784 return false; | 2785 return false; |
| 1785 | 2786 |
| 1786 // We don't ned to validate because InitExtensionID already did that. | 2787 // We don't ned to validate because InitExtensionID already did that. |
| 1787 manifest_->GetString(keys::kPublicKey, &public_key_); | 2788 manifest_->GetString(keys::kPublicKey, &public_key_); |
| 1788 | 2789 |
| 1789 // Initialize the URL. | 2790 // Initialize permissions with an empty, default permission set. |
| 2791 runtime_data_.SetActivePermissions(new ExtensionPermissionSet()); | |
| 2792 optional_permission_set_ = new ExtensionPermissionSet(); | |
| 2793 required_permission_set_ = new ExtensionPermissionSet(); | |
| 2794 | |
| 1790 extension_url_ = Extension::GetBaseURLFromExtensionId(id()); | 2795 extension_url_ = Extension::GetBaseURLFromExtensionId(id()); |
| 1791 | 2796 |
| 1792 // Initialize version. | |
| 1793 std::string version_str; | |
| 1794 if (!manifest_->GetString(keys::kVersion, &version_str)) { | |
| 1795 *error = ASCIIToUTF16(errors::kInvalidVersion); | |
| 1796 return false; | |
| 1797 } | |
| 1798 version_.reset(Version::GetVersionFromString(version_str)); | |
| 1799 if (!version_.get() || | |
| 1800 version_->components().size() > 4) { | |
| 1801 *error = ASCIIToUTF16(errors::kInvalidVersion); | |
| 1802 return false; | |
| 1803 } | |
| 1804 | |
| 1805 // Initialize name. | |
| 1806 string16 localized_name; | |
| 1807 if (!manifest_->GetString(keys::kName, &localized_name)) { | |
| 1808 *error = ASCIIToUTF16(errors::kInvalidName); | |
| 1809 return false; | |
| 1810 } | |
| 1811 base::i18n::AdjustStringForLocaleDirection(&localized_name); | |
| 1812 name_ = UTF16ToUTF8(localized_name); | |
| 1813 | |
| 1814 // Load App settings. LoadExtent at least has to be done before | 2797 // Load App settings. LoadExtent at least has to be done before |
| 1815 // ParsePermissions(), because the valid permissions depend on what type of | 2798 // ParsePermissions(), because the valid permissions depend on what type of |
| 1816 // package this is. | 2799 // package this is. |
| 1817 if (is_app() && | 2800 if (is_app() && !LoadAppFeatures(error)) |
| 1818 (!LoadExtent(keys::kWebURLs, &extent_,errors::kInvalidWebURLs, | 2801 return false; |
| 1819 errors::kInvalidWebURL, error) || | 2802 |
| 1820 !LoadLaunchURL(error) || | |
| 1821 !LoadLaunchContainer(error))) { | |
| 1822 return false; | |
| 1823 } | |
| 1824 | |
| 1825 if (is_platform_app()) { | |
| 1826 if (launch_container() != extension_misc::LAUNCH_SHELL) { | |
| 1827 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform); | |
| 1828 return false; | |
| 1829 } | |
| 1830 } else if (launch_container() == extension_misc::LAUNCH_SHELL) { | |
| 1831 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform); | |
| 1832 return false; | |
| 1833 } | |
| 1834 | |
| 1835 // Initialize the permissions (optional). | |
| 1836 ExtensionAPIPermissionSet api_permissions; | 2803 ExtensionAPIPermissionSet api_permissions; |
| 1837 URLPatternSet host_permissions; | 2804 URLPatternSet host_permissions; |
| 1838 if (!ParsePermissions(keys::kPermissions, | 2805 if (!ParsePermissions(keys::kPermissions, |
| 1839 flags, | |
| 1840 error, | 2806 error, |
| 1841 &api_permissions, | 2807 &api_permissions, |
| 1842 &host_permissions)) { | 2808 &host_permissions)) { |
| 1843 return false; | 2809 return false; |
| 1844 } | 2810 } |
| 1845 | 2811 |
| 1846 // Initialize the optional permissions (optional). | |
| 1847 ExtensionAPIPermissionSet optional_api_permissions; | 2812 ExtensionAPIPermissionSet optional_api_permissions; |
| 1848 URLPatternSet optional_host_permissions; | 2813 URLPatternSet optional_host_permissions; |
| 1849 if (!ParsePermissions(keys::kOptionalPermissions, | 2814 if (!ParsePermissions(keys::kOptionalPermissions, |
| 1850 flags, | |
| 1851 error, | 2815 error, |
| 1852 &optional_api_permissions, | 2816 &optional_api_permissions, |
| 1853 &optional_host_permissions)) { | 2817 &optional_host_permissions)) { |
| 1854 return false; | 2818 return false; |
| 1855 } | 2819 } |
| 1856 | 2820 |
| 1857 // Initialize description (if present). | |
| 1858 if (manifest_->HasKey(keys::kDescription)) { | |
| 1859 if (!manifest_->GetString(keys::kDescription, &description_)) { | |
| 1860 *error = ASCIIToUTF16(errors::kInvalidDescription); | |
| 1861 return false; | |
| 1862 } | |
| 1863 } | |
| 1864 | |
| 1865 // Initialize homepage url (if present). | |
| 1866 if (manifest_->HasKey(keys::kHomepageURL)) { | |
| 1867 std::string tmp; | |
| 1868 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) { | |
| 1869 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1870 errors::kInvalidHomepageURL, ""); | |
| 1871 return false; | |
| 1872 } | |
| 1873 homepage_url_ = GURL(tmp); | |
| 1874 if (!homepage_url_.is_valid() || | |
| 1875 (!homepage_url_.SchemeIs("http") && | |
| 1876 !homepage_url_.SchemeIs("https"))) { | |
| 1877 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1878 errors::kInvalidHomepageURL, tmp); | |
| 1879 return false; | |
| 1880 } | |
| 1881 } | |
| 1882 | |
| 1883 // Initialize update url (if present). | |
| 1884 if (manifest_->HasKey(keys::kUpdateURL)) { | |
| 1885 std::string tmp; | |
| 1886 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) { | |
| 1887 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1888 errors::kInvalidUpdateURL, ""); | |
| 1889 return false; | |
| 1890 } | |
| 1891 update_url_ = GURL(tmp); | |
| 1892 if (!update_url_.is_valid() || | |
| 1893 update_url_.has_ref()) { | |
| 1894 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1895 errors::kInvalidUpdateURL, tmp); | |
| 1896 return false; | |
| 1897 } | |
| 1898 } | |
| 1899 | |
| 1900 // Validate minimum Chrome version (if present). We don't need to store this, | |
| 1901 // since the extension is not valid if it is incorrect. | |
| 1902 if (manifest_->HasKey(keys::kMinimumChromeVersion)) { | |
| 1903 std::string minimum_version_string; | |
| 1904 if (!manifest_->GetString(keys::kMinimumChromeVersion, | |
| 1905 &minimum_version_string)) { | |
| 1906 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); | |
| 1907 return false; | |
| 1908 } | |
| 1909 | |
| 1910 scoped_ptr<Version> minimum_version( | |
| 1911 Version::GetVersionFromString(minimum_version_string)); | |
| 1912 if (!minimum_version.get()) { | |
| 1913 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion); | |
| 1914 return false; | |
| 1915 } | |
| 1916 | |
| 1917 chrome::VersionInfo current_version_info; | |
| 1918 if (!current_version_info.is_valid()) { | |
| 1919 NOTREACHED(); | |
| 1920 return false; | |
| 1921 } | |
| 1922 | |
| 1923 scoped_ptr<Version> current_version( | |
| 1924 Version::GetVersionFromString(current_version_info.Version())); | |
| 1925 if (!current_version.get()) { | |
| 1926 DCHECK(false); | |
| 1927 return false; | |
| 1928 } | |
| 1929 | |
| 1930 if (current_version->CompareTo(*minimum_version) < 0) { | |
| 1931 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1932 errors::kChromeVersionTooLow, | |
| 1933 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME), | |
| 1934 minimum_version_string); | |
| 1935 return false; | |
| 1936 } | |
| 1937 } | |
| 1938 | |
| 1939 // Initialize converted_from_user_script (if present) | |
| 1940 if (manifest_->HasKey(keys::kConvertedFromUserScript)) | |
| 1941 manifest_->GetBoolean(keys::kConvertedFromUserScript, | |
| 1942 &converted_from_user_script_); | |
| 1943 | |
| 1944 // Initialize commands (if present). | |
| 1945 if (manifest_->HasKey(keys::kCommands)) { | |
| 1946 DictionaryValue* commands = NULL; | |
| 1947 if (!manifest_->GetDictionary(keys::kCommands, &commands)) { | |
| 1948 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); | |
| 1949 return false; | |
| 1950 } | |
| 1951 | |
| 1952 int command_index = 0; | |
| 1953 for (DictionaryValue::key_iterator iter = commands->begin_keys(); | |
| 1954 iter != commands->end_keys(); ++iter) { | |
| 1955 ++command_index; | |
| 1956 | |
| 1957 DictionaryValue* command = NULL; | |
| 1958 if (!commands->GetDictionary(*iter, &command)) { | |
| 1959 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1960 errors::kInvalidKeyBindingDictionary, | |
| 1961 base::IntToString(command_index)); | |
| 1962 return false; | |
| 1963 } | |
| 1964 | |
| 1965 ExtensionKeybinding binding; | |
| 1966 if (!binding.Parse(command, *iter, command_index, error)) | |
| 1967 return false; // |error| already set. | |
| 1968 | |
| 1969 commands_.push_back(binding); | |
| 1970 } | |
| 1971 } | |
| 1972 | |
| 1973 // Initialize icons (if present). | |
| 1974 if (manifest_->HasKey(keys::kIcons)) { | |
| 1975 DictionaryValue* icons_value = NULL; | |
| 1976 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) { | |
| 1977 *error = ASCIIToUTF16(errors::kInvalidIcons); | |
| 1978 return false; | |
| 1979 } | |
| 1980 | |
| 1981 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) { | |
| 1982 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]); | |
| 1983 if (icons_value->HasKey(key)) { | |
| 1984 std::string icon_path; | |
| 1985 if (!icons_value->GetString(key, &icon_path)) { | |
| 1986 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1987 errors::kInvalidIconPath, key); | |
| 1988 return false; | |
| 1989 } | |
| 1990 | |
| 1991 if (!icon_path.empty() && icon_path[0] == '/') | |
| 1992 icon_path = icon_path.substr(1); | |
| 1993 | |
| 1994 if (icon_path.empty()) { | |
| 1995 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 1996 errors::kInvalidIconPath, key); | |
| 1997 return false; | |
| 1998 } | |
| 1999 | |
| 2000 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path); | |
| 2001 } | |
| 2002 } | |
| 2003 } | |
| 2004 | |
| 2005 // Initialize themes (if present). | |
| 2006 if (manifest_->HasKey(keys::kTheme)) { | |
| 2007 DictionaryValue* theme_value = NULL; | |
| 2008 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) { | |
| 2009 *error = ASCIIToUTF16(errors::kInvalidTheme); | |
| 2010 return false; | |
| 2011 } | |
| 2012 | |
| 2013 DictionaryValue* images_value = NULL; | |
| 2014 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { | |
| 2015 // Validate that the images are all strings | |
| 2016 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); | |
| 2017 iter != images_value->end_keys(); ++iter) { | |
| 2018 std::string val; | |
| 2019 if (!images_value->GetString(*iter, &val)) { | |
| 2020 *error = ASCIIToUTF16(errors::kInvalidThemeImages); | |
| 2021 return false; | |
| 2022 } | |
| 2023 } | |
| 2024 theme_images_.reset(images_value->DeepCopy()); | |
| 2025 } | |
| 2026 | |
| 2027 DictionaryValue* colors_value = NULL; | |
| 2028 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { | |
| 2029 // Validate that the colors are RGB or RGBA lists | |
| 2030 for (DictionaryValue::key_iterator iter = colors_value->begin_keys(); | |
| 2031 iter != colors_value->end_keys(); ++iter) { | |
| 2032 ListValue* color_list = NULL; | |
| 2033 double alpha = 0.0; | |
| 2034 int color = 0; | |
| 2035 // The color must be a list | |
| 2036 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) || | |
| 2037 // And either 3 items (RGB) or 4 (RGBA) | |
| 2038 ((color_list->GetSize() != 3) && | |
| 2039 ((color_list->GetSize() != 4) || | |
| 2040 // For RGBA, the fourth item must be a real or int alpha value. | |
| 2041 // Note that GetDouble() can get an integer value. | |
| 2042 !color_list->GetDouble(3, &alpha))) || | |
| 2043 // For both RGB and RGBA, the first three items must be ints (R,G,B) | |
| 2044 !color_list->GetInteger(0, &color) || | |
| 2045 !color_list->GetInteger(1, &color) || | |
| 2046 !color_list->GetInteger(2, &color)) { | |
| 2047 *error = ASCIIToUTF16(errors::kInvalidThemeColors); | |
| 2048 return false; | |
| 2049 } | |
| 2050 } | |
| 2051 theme_colors_.reset(colors_value->DeepCopy()); | |
| 2052 } | |
| 2053 | |
| 2054 DictionaryValue* tints_value = NULL; | |
| 2055 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) { | |
| 2056 // Validate that the tints are all reals. | |
| 2057 for (DictionaryValue::key_iterator iter = tints_value->begin_keys(); | |
| 2058 iter != tints_value->end_keys(); ++iter) { | |
| 2059 ListValue* tint_list = NULL; | |
| 2060 double v = 0.0; | |
| 2061 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) || | |
| 2062 tint_list->GetSize() != 3 || | |
| 2063 !tint_list->GetDouble(0, &v) || | |
| 2064 !tint_list->GetDouble(1, &v) || | |
| 2065 !tint_list->GetDouble(2, &v)) { | |
| 2066 *error = ASCIIToUTF16(errors::kInvalidThemeTints); | |
| 2067 return false; | |
| 2068 } | |
| 2069 } | |
| 2070 theme_tints_.reset(tints_value->DeepCopy()); | |
| 2071 } | |
| 2072 | |
| 2073 DictionaryValue* display_properties_value = NULL; | |
| 2074 if (theme_value->GetDictionary(keys::kThemeDisplayProperties, | |
| 2075 &display_properties_value)) { | |
| 2076 theme_display_properties_.reset( | |
| 2077 display_properties_value->DeepCopy()); | |
| 2078 } | |
| 2079 | |
| 2080 return true; | |
| 2081 } | |
| 2082 | |
| 2083 // Initialize plugins (optional). | |
| 2084 if (manifest_->HasKey(keys::kPlugins)) { | |
| 2085 ListValue* list_value = NULL; | |
| 2086 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | |
| 2087 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 2088 return false; | |
| 2089 } | |
| 2090 | |
| 2091 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2092 DictionaryValue* plugin_value = NULL; | |
| 2093 std::string path_str; | |
| 2094 bool is_public = false; | |
| 2095 | |
| 2096 if (!list_value->GetDictionary(i, &plugin_value)) { | |
| 2097 *error = ASCIIToUTF16(errors::kInvalidPlugins); | |
| 2098 return false; | |
| 2099 } | |
| 2100 | |
| 2101 // Get plugins[i].path. | |
| 2102 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) { | |
| 2103 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2104 errors::kInvalidPluginsPath, base::IntToString(i)); | |
| 2105 return false; | |
| 2106 } | |
| 2107 | |
| 2108 // Get plugins[i].content (optional). | |
| 2109 if (plugin_value->HasKey(keys::kPluginsPublic)) { | |
| 2110 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) { | |
| 2111 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2112 errors::kInvalidPluginsPublic, base::IntToString(i)); | |
| 2113 return false; | |
| 2114 } | |
| 2115 } | |
| 2116 | |
| 2117 // We don't allow extension plugins to run on Chrome OS. We still | |
| 2118 // parse the manifest entry so that error messages are consistently | |
| 2119 // displayed across platforms. | |
| 2120 #if !defined(OS_CHROMEOS) | |
| 2121 plugins_.push_back(PluginInfo()); | |
| 2122 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str)); | |
| 2123 plugins_.back().is_public = is_public; | |
| 2124 #endif | |
| 2125 } | |
| 2126 } | |
| 2127 | |
| 2128 if (manifest_->HasKey(keys::kNaClModules)) { | |
| 2129 ListValue* list_value = NULL; | |
| 2130 if (!manifest_->GetList(keys::kNaClModules, &list_value)) { | |
| 2131 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 2132 return false; | |
| 2133 } | |
| 2134 | |
| 2135 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2136 DictionaryValue* module_value = NULL; | |
| 2137 std::string path_str; | |
| 2138 std::string mime_type; | |
| 2139 | |
| 2140 if (!list_value->GetDictionary(i, &module_value)) { | |
| 2141 *error = ASCIIToUTF16(errors::kInvalidNaClModules); | |
| 2142 return false; | |
| 2143 } | |
| 2144 | |
| 2145 // Get nacl_modules[i].path. | |
| 2146 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) { | |
| 2147 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2148 errors::kInvalidNaClModulesPath, base::IntToString(i)); | |
| 2149 return false; | |
| 2150 } | |
| 2151 | |
| 2152 // Get nacl_modules[i].mime_type. | |
| 2153 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) { | |
| 2154 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2155 errors::kInvalidNaClModulesMIMEType, base::IntToString(i)); | |
| 2156 return false; | |
| 2157 } | |
| 2158 | |
| 2159 nacl_modules_.push_back(NaClModuleInfo()); | |
| 2160 nacl_modules_.back().url = GetResourceURL(path_str); | |
| 2161 nacl_modules_.back().mime_type = mime_type; | |
| 2162 } | |
| 2163 } | |
| 2164 | |
| 2165 // Initialize content scripts (optional). | |
| 2166 if (manifest_->HasKey(keys::kContentScripts)) { | |
| 2167 ListValue* list_value; | |
| 2168 if (!manifest_->GetList(keys::kContentScripts, &list_value)) { | |
| 2169 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList); | |
| 2170 return false; | |
| 2171 } | |
| 2172 | |
| 2173 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2174 DictionaryValue* content_script = NULL; | |
| 2175 if (!list_value->GetDictionary(i, &content_script)) { | |
| 2176 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2177 errors::kInvalidContentScript, base::IntToString(i)); | |
| 2178 return false; | |
| 2179 } | |
| 2180 | |
| 2181 UserScript script; | |
| 2182 if (!LoadUserScriptHelper(content_script, i, flags, error, &script)) | |
| 2183 return false; // Failed to parse script context definition. | |
| 2184 script.set_extension_id(id()); | |
| 2185 if (converted_from_user_script_) { | |
| 2186 script.set_emulate_greasemonkey(true); | |
| 2187 script.set_match_all_frames(true); // Greasemonkey matches all frames. | |
| 2188 } | |
| 2189 content_scripts_.push_back(script); | |
| 2190 } | |
| 2191 } | |
| 2192 | |
| 2193 // Initialize web accessible resources (optional). | |
| 2194 if (manifest_->HasKey(keys::kWebAccessibleResources)) { | |
| 2195 ListValue* list_value; | |
| 2196 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) { | |
| 2197 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList); | |
| 2198 return false; | |
| 2199 } | |
| 2200 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2201 std::string relative_path; | |
| 2202 if (!list_value->GetString(i, &relative_path)) { | |
| 2203 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2204 errors::kInvalidWebAccessibleResource, base::IntToString(i)); | |
| 2205 return false; | |
| 2206 } | |
| 2207 if (relative_path[0] != '/') | |
| 2208 relative_path = '/' + relative_path; | |
| 2209 web_accessible_resources_.insert(relative_path); | |
| 2210 } | |
| 2211 } | |
| 2212 | |
| 2213 // Initialize page action (optional). | |
| 2214 DictionaryValue* page_action_value = NULL; | |
| 2215 | |
| 2216 if (manifest_->HasKey(keys::kPageActions)) { | |
| 2217 ListValue* list_value = NULL; | |
| 2218 if (!manifest_->GetList(keys::kPageActions, &list_value)) { | |
| 2219 *error = ASCIIToUTF16(errors::kInvalidPageActionsList); | |
| 2220 return false; | |
| 2221 } | |
| 2222 | |
| 2223 size_t list_value_length = list_value->GetSize(); | |
| 2224 | |
| 2225 if (list_value_length == 0u) { | |
| 2226 // A list with zero items is allowed, and is equivalent to not having | |
| 2227 // a page_actions key in the manifest. Don't set |page_action_value|. | |
| 2228 } else if (list_value_length == 1u) { | |
| 2229 if (!list_value->GetDictionary(0, &page_action_value)) { | |
| 2230 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2231 return false; | |
| 2232 } | |
| 2233 } else { // list_value_length > 1u. | |
| 2234 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize); | |
| 2235 return false; | |
| 2236 } | |
| 2237 } else if (manifest_->HasKey(keys::kPageAction)) { | |
| 2238 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { | |
| 2239 *error = ASCIIToUTF16(errors::kInvalidPageAction); | |
| 2240 return false; | |
| 2241 } | |
| 2242 } | |
| 2243 | |
| 2244 // If page_action_value is not NULL, then there was a valid page action. | |
| 2245 if (page_action_value) { | |
| 2246 page_action_.reset( | |
| 2247 LoadExtensionActionHelper(page_action_value, error)); | |
| 2248 if (!page_action_.get()) | |
| 2249 return false; // Failed to parse page action definition. | |
| 2250 } | |
| 2251 | |
| 2252 // Initialize browser action (optional). | |
| 2253 if (manifest_->HasKey(keys::kBrowserAction)) { | |
| 2254 DictionaryValue* browser_action_value = NULL; | |
| 2255 if (!manifest_->GetDictionary(keys::kBrowserAction, | |
| 2256 &browser_action_value)) { | |
| 2257 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); | |
| 2258 return false; | |
| 2259 } | |
| 2260 | |
| 2261 browser_action_.reset( | |
| 2262 LoadExtensionActionHelper(browser_action_value, error)); | |
| 2263 if (!browser_action_.get()) | |
| 2264 return false; // Failed to parse browser action definition. | |
| 2265 } | |
| 2266 | |
| 2267 // Initialize file browser actions (optional). | |
| 2268 if (manifest_->HasKey(keys::kFileBrowserHandlers)) { | |
| 2269 ListValue* file_browser_handlers_value = NULL; | |
| 2270 if (!manifest_->GetList(keys::kFileBrowserHandlers, | |
| 2271 &file_browser_handlers_value)) { | |
| 2272 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | |
| 2273 return false; | |
| 2274 } | |
| 2275 | |
| 2276 file_browser_handlers_.reset( | |
| 2277 LoadFileBrowserHandlers(file_browser_handlers_value, error)); | |
| 2278 if (!file_browser_handlers_.get()) | |
| 2279 return false; // Failed to parse file browser actions definition. | |
| 2280 } | |
| 2281 | |
| 2282 // App isolation. | 2821 // App isolation. |
| 2283 if (api_permissions.count(ExtensionAPIPermission::kExperimental)) { | 2822 if (api_permissions.count(ExtensionAPIPermission::kExperimental) && |
| 2284 if (is_app() && !LoadAppIsolation(error)) | 2823 !LoadAppIsolation(error)) |
| 2285 return false; | 2824 return false; |
| 2286 } | 2825 |
| 2287 | 2826 if (!LoadSharedFeatures(api_permissions, error)) |
| 2288 // Initialize options page url (optional). | 2827 return false; |
| 2289 if (manifest_->HasKey(keys::kOptionsPage)) { | 2828 |
| 2290 std::string options_str; | 2829 if (!LoadExtensionFeatures(api_permissions, error)) |
| 2291 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) { | 2830 return false; |
| 2292 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | 2831 |
| 2293 return false; | 2832 if (!LoadThemeFeatures(error)) |
| 2294 } | 2833 return false; |
| 2295 | |
| 2296 if (is_hosted_app()) { | |
| 2297 // hosted apps require an absolute URL. | |
| 2298 GURL options_url(options_str); | |
| 2299 if (!options_url.is_valid() || | |
| 2300 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) { | |
| 2301 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp); | |
| 2302 return false; | |
| 2303 } | |
| 2304 options_url_ = options_url; | |
| 2305 } else { | |
| 2306 GURL absolute(options_str); | |
| 2307 if (absolute.is_valid()) { | |
| 2308 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage); | |
| 2309 return false; | |
| 2310 } | |
| 2311 options_url_ = GetResourceURL(options_str); | |
| 2312 if (!options_url_.is_valid()) { | |
| 2313 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 2314 return false; | |
| 2315 } | |
| 2316 } | |
| 2317 } | |
| 2318 | |
| 2319 if (!LoadBackgroundScripts(error)) | |
| 2320 return false; | |
| 2321 | |
| 2322 if (!LoadBackgroundPage(api_permissions, error)) | |
| 2323 return false; | |
| 2324 | |
| 2325 if (!LoadBackgroundPersistent(api_permissions, error)) | |
| 2326 return false; | |
| 2327 | |
| 2328 if (manifest_->HasKey(keys::kDefaultLocale)) { | |
| 2329 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) || | |
| 2330 !l10n_util::IsValidLocaleSyntax(default_locale_)) { | |
| 2331 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale); | |
| 2332 return false; | |
| 2333 } | |
| 2334 } | |
| 2335 | |
| 2336 // Chrome URL overrides (optional) | |
| 2337 if (manifest_->HasKey(keys::kChromeURLOverrides)) { | |
| 2338 DictionaryValue* overrides = NULL; | |
| 2339 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) { | |
| 2340 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2341 return false; | |
| 2342 } | |
| 2343 | |
| 2344 // Validate that the overrides are all strings | |
| 2345 for (DictionaryValue::key_iterator iter = overrides->begin_keys(); | |
| 2346 iter != overrides->end_keys(); ++iter) { | |
| 2347 std::string page = *iter; | |
| 2348 std::string val; | |
| 2349 // Restrict override pages to a list of supported URLs. | |
| 2350 if ((page != chrome::kChromeUINewTabHost && | |
| 2351 #if defined(USE_VIRTUAL_KEYBOARD) | |
| 2352 page != chrome::kChromeUIKeyboardHost && | |
| 2353 #endif | |
| 2354 #if defined(OS_CHROMEOS) | |
| 2355 page != chrome::kChromeUIActivationMessageHost && | |
| 2356 #endif | |
| 2357 page != chrome::kChromeUIBookmarksHost && | |
| 2358 page != chrome::kChromeUIHistoryHost | |
| 2359 #if defined(FILE_MANAGER_EXTENSION) | |
| 2360 && | |
| 2361 !(location() == COMPONENT && | |
| 2362 page == chrome::kChromeUIFileManagerHost) | |
| 2363 #endif | |
| 2364 ) || | |
| 2365 !overrides->GetStringWithoutPathExpansion(*iter, &val)) { | |
| 2366 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides); | |
| 2367 return false; | |
| 2368 } | |
| 2369 // Replace the entry with a fully qualified chrome-extension:// URL. | |
| 2370 chrome_url_overrides_[page] = GetResourceURL(val); | |
| 2371 } | |
| 2372 | |
| 2373 // An extension may override at most one page. | |
| 2374 if (overrides->size() > 1) { | |
| 2375 *error = ASCIIToUTF16(errors::kMultipleOverrides); | |
| 2376 return false; | |
| 2377 } | |
| 2378 } | |
| 2379 | |
| 2380 if (manifest_->HasKey(keys::kInputComponents)) { | |
| 2381 ListValue* list_value = NULL; | |
| 2382 if (!manifest_->GetList(keys::kInputComponents, &list_value)) { | |
| 2383 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 2384 return false; | |
| 2385 } | |
| 2386 | |
| 2387 for (size_t i = 0; i < list_value->GetSize(); ++i) { | |
| 2388 DictionaryValue* module_value = NULL; | |
| 2389 std::string name_str; | |
| 2390 InputComponentType type; | |
| 2391 std::string id_str; | |
| 2392 std::string description_str; | |
| 2393 std::string language_str; | |
| 2394 std::set<std::string> layouts; | |
| 2395 std::string shortcut_keycode_str; | |
| 2396 bool shortcut_alt = false; | |
| 2397 bool shortcut_ctrl = false; | |
| 2398 bool shortcut_shift = false; | |
| 2399 | |
| 2400 if (!list_value->GetDictionary(i, &module_value)) { | |
| 2401 *error = ASCIIToUTF16(errors::kInvalidInputComponents); | |
| 2402 return false; | |
| 2403 } | |
| 2404 | |
| 2405 // Get input_components[i].name. | |
| 2406 if (!module_value->GetString(keys::kName, &name_str)) { | |
| 2407 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2408 errors::kInvalidInputComponentName, base::IntToString(i)); | |
| 2409 return false; | |
| 2410 } | |
| 2411 | |
| 2412 // Get input_components[i].type. | |
| 2413 std::string type_str; | |
| 2414 if (module_value->GetString(keys::kType, &type_str)) { | |
| 2415 if (type_str == "ime") { | |
| 2416 type = INPUT_COMPONENT_TYPE_IME; | |
| 2417 } else if (type_str == "virtual_keyboard") { | |
| 2418 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) { | |
| 2419 // Virtual Keyboards require the experimental flag. | |
| 2420 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2421 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2422 return false; | |
| 2423 } | |
| 2424 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD; | |
| 2425 } else { | |
| 2426 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2427 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2428 return false; | |
| 2429 } | |
| 2430 } else { | |
| 2431 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2432 errors::kInvalidInputComponentType, base::IntToString(i)); | |
| 2433 return false; | |
| 2434 } | |
| 2435 | |
| 2436 // Get input_components[i].id. | |
| 2437 if (!module_value->GetString(keys::kId, &id_str)) { | |
| 2438 id_str = ""; | |
| 2439 } | |
| 2440 | |
| 2441 // Get input_components[i].description. | |
| 2442 if (!module_value->GetString(keys::kDescription, &description_str)) { | |
| 2443 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2444 errors::kInvalidInputComponentDescription, base::IntToString(i)); | |
| 2445 return false; | |
| 2446 } | |
| 2447 | |
| 2448 // Get input_components[i].language. | |
| 2449 if (!module_value->GetString(keys::kLanguage, &language_str)) { | |
| 2450 language_str = ""; | |
| 2451 } | |
| 2452 | |
| 2453 // Get input_components[i].layouts. | |
| 2454 ListValue* layouts_value = NULL; | |
| 2455 if (!module_value->GetList(keys::kLayouts, &layouts_value)) { | |
| 2456 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts); | |
| 2457 return false; | |
| 2458 } | |
| 2459 | |
| 2460 for (size_t j = 0; j < layouts_value->GetSize(); ++j) { | |
| 2461 std::string layout_name_str; | |
| 2462 if (!layouts_value->GetString(j, &layout_name_str)) { | |
| 2463 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2464 errors::kInvalidInputComponentLayoutName, base::IntToString(i), | |
| 2465 base::IntToString(j)); | |
| 2466 return false; | |
| 2467 } | |
| 2468 layouts.insert(layout_name_str); | |
| 2469 } | |
| 2470 | |
| 2471 if (module_value->HasKey(keys::kShortcutKey)) { | |
| 2472 DictionaryValue* shortcut_value = NULL; | |
| 2473 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) { | |
| 2474 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2475 errors::kInvalidInputComponentShortcutKey, base::IntToString(i)); | |
| 2476 return false; | |
| 2477 } | |
| 2478 | |
| 2479 // Get input_components[i].shortcut_keycode. | |
| 2480 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) { | |
| 2481 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2482 errors::kInvalidInputComponentShortcutKeycode, | |
| 2483 base::IntToString(i)); | |
| 2484 return false; | |
| 2485 } | |
| 2486 | |
| 2487 // Get input_components[i].shortcut_alt. | |
| 2488 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) { | |
| 2489 shortcut_alt = false; | |
| 2490 } | |
| 2491 | |
| 2492 // Get input_components[i].shortcut_ctrl. | |
| 2493 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) { | |
| 2494 shortcut_ctrl = false; | |
| 2495 } | |
| 2496 | |
| 2497 // Get input_components[i].shortcut_shift. | |
| 2498 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) { | |
| 2499 shortcut_shift = false; | |
| 2500 } | |
| 2501 } | |
| 2502 | |
| 2503 input_components_.push_back(InputComponentInfo()); | |
| 2504 input_components_.back().name = name_str; | |
| 2505 input_components_.back().type = type; | |
| 2506 input_components_.back().id = id_str; | |
| 2507 input_components_.back().description = description_str; | |
| 2508 input_components_.back().language = language_str; | |
| 2509 input_components_.back().layouts.insert(layouts.begin(), layouts.end()); | |
| 2510 input_components_.back().shortcut_keycode = shortcut_keycode_str; | |
| 2511 input_components_.back().shortcut_alt = shortcut_alt; | |
| 2512 input_components_.back().shortcut_ctrl = shortcut_ctrl; | |
| 2513 input_components_.back().shortcut_shift = shortcut_shift; | |
| 2514 } | |
| 2515 } | |
| 2516 | |
| 2517 if (manifest_->HasKey(keys::kOmnibox)) { | |
| 2518 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) || | |
| 2519 omnibox_keyword_.empty()) { | |
| 2520 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword); | |
| 2521 return false; | |
| 2522 } | |
| 2523 } | |
| 2524 | |
| 2525 if (manifest_->HasKey(keys::kContentSecurityPolicy)) { | |
| 2526 std::string content_security_policy; | |
| 2527 if (!manifest_->GetString(keys::kContentSecurityPolicy, | |
| 2528 &content_security_policy)) { | |
| 2529 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2530 return false; | |
| 2531 } | |
| 2532 if (!ContentSecurityPolicyIsLegal(content_security_policy)) { | |
| 2533 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2534 return false; | |
| 2535 } | |
| 2536 if (manifest_version_ >= 2 && | |
| 2537 !ContentSecurityPolicyIsSecure(content_security_policy)) { | |
| 2538 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy); | |
| 2539 return false; | |
| 2540 } | |
| 2541 | |
| 2542 content_security_policy_ = content_security_policy; | |
| 2543 } else if (manifest_version_ >= 2) { | |
| 2544 // Manifest version 2 introduced a default Content-Security-Policy. | |
| 2545 // TODO(abarth): Should we continue to let extensions override the | |
| 2546 // default Content-Security-Policy? | |
| 2547 content_security_policy_ = kDefaultContentSecurityPolicy; | |
| 2548 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_)); | |
| 2549 } | |
| 2550 | |
| 2551 // Initialize devtools page url (optional). | |
| 2552 if (manifest_->HasKey(keys::kDevToolsPage)) { | |
| 2553 std::string devtools_str; | |
| 2554 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) { | |
| 2555 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage); | |
| 2556 return false; | |
| 2557 } | |
| 2558 devtools_url_ = GetResourceURL(devtools_str); | |
| 2559 } | |
| 2560 | |
| 2561 // Initialize text-to-speech voices (optional). | |
| 2562 if (manifest_->HasKey(keys::kTtsEngine)) { | |
| 2563 DictionaryValue* tts_dict = NULL; | |
| 2564 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) { | |
| 2565 *error = ASCIIToUTF16(errors::kInvalidTts); | |
| 2566 return false; | |
| 2567 } | |
| 2568 | |
| 2569 if (tts_dict->HasKey(keys::kTtsVoices)) { | |
| 2570 ListValue* tts_voices = NULL; | |
| 2571 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) { | |
| 2572 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2573 return false; | |
| 2574 } | |
| 2575 | |
| 2576 for (size_t i = 0; i < tts_voices->GetSize(); i++) { | |
| 2577 DictionaryValue* one_tts_voice = NULL; | |
| 2578 if (!tts_voices->GetDictionary(i, &one_tts_voice)) { | |
| 2579 *error = ASCIIToUTF16(errors::kInvalidTtsVoices); | |
| 2580 return false; | |
| 2581 } | |
| 2582 | |
| 2583 TtsVoice voice_data; | |
| 2584 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) { | |
| 2585 if (!one_tts_voice->GetString( | |
| 2586 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) { | |
| 2587 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName); | |
| 2588 return false; | |
| 2589 } | |
| 2590 } | |
| 2591 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) { | |
| 2592 if (!one_tts_voice->GetString( | |
| 2593 keys::kTtsVoicesLang, &voice_data.lang) || | |
| 2594 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) { | |
| 2595 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang); | |
| 2596 return false; | |
| 2597 } | |
| 2598 } | |
| 2599 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) { | |
| 2600 if (!one_tts_voice->GetString( | |
| 2601 keys::kTtsVoicesGender, &voice_data.gender) || | |
| 2602 (voice_data.gender != keys::kTtsGenderMale && | |
| 2603 voice_data.gender != keys::kTtsGenderFemale)) { | |
| 2604 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender); | |
| 2605 return false; | |
| 2606 } | |
| 2607 } | |
| 2608 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) { | |
| 2609 ListValue* event_types_list; | |
| 2610 if (!one_tts_voice->GetList( | |
| 2611 keys::kTtsVoicesEventTypes, &event_types_list)) { | |
| 2612 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2613 return false; | |
| 2614 } | |
| 2615 for (size_t i = 0; i < event_types_list->GetSize(); i++) { | |
| 2616 std::string event_type; | |
| 2617 if (!event_types_list->GetString(i, &event_type)) { | |
| 2618 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2619 return false; | |
| 2620 } | |
| 2621 if (event_type != keys::kTtsVoicesEventTypeEnd && | |
| 2622 event_type != keys::kTtsVoicesEventTypeError && | |
| 2623 event_type != keys::kTtsVoicesEventTypeMarker && | |
| 2624 event_type != keys::kTtsVoicesEventTypeSentence && | |
| 2625 event_type != keys::kTtsVoicesEventTypeStart && | |
| 2626 event_type != keys::kTtsVoicesEventTypeWord) { | |
| 2627 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2628 return false; | |
| 2629 } | |
| 2630 if (voice_data.event_types.find(event_type) != | |
| 2631 voice_data.event_types.end()) { | |
| 2632 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes); | |
| 2633 return false; | |
| 2634 } | |
| 2635 voice_data.event_types.insert(event_type); | |
| 2636 } | |
| 2637 } | |
| 2638 | |
| 2639 tts_voices_.push_back(voice_data); | |
| 2640 } | |
| 2641 } | |
| 2642 } | |
| 2643 | |
| 2644 // Initialize web intents (optional). | |
| 2645 if (!LoadWebIntentServices(error)) | |
| 2646 return false; | |
| 2647 | |
| 2648 // Initialize incognito behavior. Apps default to split mode, extensions | |
| 2649 // default to spanning. | |
| 2650 incognito_split_mode_ = is_app(); | |
| 2651 if (manifest_->HasKey(keys::kIncognito)) { | |
| 2652 std::string value; | |
| 2653 if (!manifest_->GetString(keys::kIncognito, &value)) { | |
| 2654 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2655 return false; | |
| 2656 } | |
| 2657 if (value == values::kIncognitoSpanning) { | |
| 2658 incognito_split_mode_ = false; | |
| 2659 } else if (value == values::kIncognitoSplit) { | |
| 2660 incognito_split_mode_ = true; | |
| 2661 } else { | |
| 2662 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior); | |
| 2663 return false; | |
| 2664 } | |
| 2665 } | |
| 2666 | |
| 2667 // Initialize offline-enabled status. Defaults to false. | |
| 2668 if (manifest_->HasKey(keys::kOfflineEnabled)) { | |
| 2669 if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) { | |
| 2670 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled); | |
| 2671 return false; | |
| 2672 } | |
| 2673 } | |
| 2674 | |
| 2675 // Initialize requirements (optional). Not actually persisted (they're only | |
| 2676 // used by the store), but still validated. | |
| 2677 if (manifest_->HasKey(keys::kRequirements)) { | |
| 2678 DictionaryValue* requirements_value = NULL; | |
| 2679 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) { | |
| 2680 *error = ASCIIToUTF16(errors::kInvalidRequirements); | |
| 2681 return false; | |
| 2682 } | |
| 2683 | |
| 2684 for (DictionaryValue::key_iterator it = requirements_value->begin_keys(); | |
| 2685 it != requirements_value->end_keys(); ++it) { | |
| 2686 DictionaryValue* requirement_value; | |
| 2687 if (!requirements_value->GetDictionaryWithoutPathExpansion( | |
| 2688 *it, &requirement_value)) { | |
| 2689 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 2690 errors::kInvalidRequirement, *it); | |
| 2691 return false; | |
| 2692 } | |
| 2693 } | |
| 2694 } | |
| 2695 | 2834 |
| 2696 if (HasMultipleUISurfaces()) { | 2835 if (HasMultipleUISurfaces()) { |
| 2697 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); | 2836 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); |
| 2698 return false; | 2837 return false; |
| 2699 } | 2838 } |
| 2700 | 2839 |
| 2701 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( | 2840 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( |
| 2702 this, api_permissions, host_permissions)); | 2841 this, api_permissions, host_permissions)); |
| 2703 required_permission_set_ = new ExtensionPermissionSet( | 2842 required_permission_set_ = new ExtensionPermissionSet( |
| 2704 this, api_permissions, host_permissions); | 2843 this, api_permissions, host_permissions); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2854 GURL Extension::GetIconURL(int size, | 2993 GURL Extension::GetIconURL(int size, |
| 2855 ExtensionIconSet::MatchType match_type) const { | 2994 ExtensionIconSet::MatchType match_type) const { |
| 2856 std::string path = icons().Get(size, match_type); | 2995 std::string path = icons().Get(size, match_type); |
| 2857 if (path.empty()) | 2996 if (path.empty()) |
| 2858 return GURL(); | 2997 return GURL(); |
| 2859 else | 2998 else |
| 2860 return GetResourceURL(path); | 2999 return GetResourceURL(path); |
| 2861 } | 3000 } |
| 2862 | 3001 |
| 2863 bool Extension::ParsePermissions(const char* key, | 3002 bool Extension::ParsePermissions(const char* key, |
| 2864 int flags, | |
| 2865 string16* error, | 3003 string16* error, |
| 2866 ExtensionAPIPermissionSet* api_permissions, | 3004 ExtensionAPIPermissionSet* api_permissions, |
| 2867 URLPatternSet* host_permissions) { | 3005 URLPatternSet* host_permissions) { |
| 2868 if (manifest_->HasKey(key)) { | 3006 if (manifest_->HasKey(key)) { |
| 2869 ListValue* permissions = NULL; | 3007 ListValue* permissions = NULL; |
| 2870 if (!manifest_->GetList(key, &permissions)) { | 3008 if (!manifest_->GetList(key, &permissions)) { |
| 2871 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 3009 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 2872 errors::kInvalidPermissions, ""); | 3010 errors::kInvalidPermissions, ""); |
| 2873 return false; | 3011 return false; |
| 2874 } | 3012 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 2905 return false; | 3043 return false; |
| 2906 } | 3044 } |
| 2907 | 3045 |
| 2908 // The path component is not used for host permissions, so we force it | 3046 // The path component is not used for host permissions, so we force it |
| 2909 // to match all paths. | 3047 // to match all paths. |
| 2910 pattern.SetPath("/*"); | 3048 pattern.SetPath("/*"); |
| 2911 | 3049 |
| 2912 if (pattern.MatchesScheme(chrome::kFileScheme) && | 3050 if (pattern.MatchesScheme(chrome::kFileScheme) && |
| 2913 !CanExecuteScriptEverywhere()) { | 3051 !CanExecuteScriptEverywhere()) { |
| 2914 wants_file_access_ = true; | 3052 wants_file_access_ = true; |
| 2915 if (!(flags & ALLOW_FILE_ACCESS)) | 3053 if (!(creation_flags_ & ALLOW_FILE_ACCESS)) |
| 2916 pattern.SetValidSchemes( | 3054 pattern.SetValidSchemes( |
| 2917 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); | 3055 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); |
| 2918 } | 3056 } |
| 2919 | 3057 |
| 2920 host_permissions->AddPattern(pattern); | 3058 host_permissions->AddPattern(pattern); |
| 2921 } | 3059 } |
| 2922 | 3060 |
| 2923 // If it's not a host permission, then it's probably an unknown API | 3061 // If it's not a host permission, then it's probably an unknown API |
| 2924 // permission. Do not throw an error so extensions can retain | 3062 // permission. Do not throw an error so extensions can retain |
| 2925 // backwards compatability (http://crbug.com/42742). | 3063 // backwards compatability (http://crbug.com/42742). |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3094 // extension with options. All other menu items like uninstall have | 3232 // extension with options. All other menu items like uninstall have |
| 3095 // no sense for component extensions. | 3233 // no sense for component extensions. |
| 3096 return location() != Extension::COMPONENT; | 3234 return location() != Extension::COMPONENT; |
| 3097 } | 3235 } |
| 3098 | 3236 |
| 3099 bool Extension::CanSpecifyAPIPermission( | 3237 bool Extension::CanSpecifyAPIPermission( |
| 3100 const ExtensionAPIPermission* permission, | 3238 const ExtensionAPIPermission* permission, |
| 3101 string16* error) const { | 3239 string16* error) const { |
| 3102 if (location() == Extension::COMPONENT) | 3240 if (location() == Extension::COMPONENT) |
| 3103 return true; | 3241 return true; |
| 3104 | |
| 3105 bool access_denied = false; | 3242 bool access_denied = false; |
| 3106 if (permission->HasWhitelist()) { | 3243 if (permission->HasWhitelist()) { |
| 3107 if (permission->IsWhitelisted(id())) | 3244 if (permission->IsWhitelisted(id())) |
| 3108 return true; | 3245 return true; |
| 3109 else | 3246 else |
| 3110 access_denied = true; | 3247 access_denied = true; |
| 3111 } else if (permission->is_component_only()) { | 3248 } else if (permission->is_component_only()) { |
| 3112 access_denied = true; | 3249 access_denied = true; |
| 3113 } | 3250 } |
| 3114 | 3251 |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3272 return SYNC_TYPE_APP; | 3409 return SYNC_TYPE_APP; |
| 3273 | 3410 |
| 3274 default: | 3411 default: |
| 3275 return SYNC_TYPE_NONE; | 3412 return SYNC_TYPE_NONE; |
| 3276 } | 3413 } |
| 3277 } | 3414 } |
| 3278 | 3415 |
| 3279 bool Extension::IsSyncable() const { | 3416 bool Extension::IsSyncable() const { |
| 3280 // TODO(akalin): Figure out if we need to allow some other types. | 3417 // TODO(akalin): Figure out if we need to allow some other types. |
| 3281 | 3418 |
| 3282 // We want to sync any extensions that are shown in the luancher because | 3419 // We want to sync any extensions that are shown in the launcher because |
| 3283 // their positions should sync. | 3420 // their positions should sync. |
| 3284 return location() == Extension::INTERNAL || | 3421 return location() == Extension::INTERNAL || |
| 3285 ShouldDisplayInLauncher(); | 3422 ShouldDisplayInLauncher(); |
| 3286 } | 3423 } |
| 3287 | 3424 |
| 3288 bool Extension::ShouldDisplayInLauncher() const { | 3425 bool Extension::ShouldDisplayInLauncher() const { |
| 3289 // All apps should be displayed on the NTP except for the Cloud Print App. | 3426 // All apps should be displayed on the NTP except for the Cloud Print App. |
| 3290 return is_app() && id() != extension_misc::kCloudPrintAppId; | 3427 return is_app() && id() != extension_misc::kCloudPrintAppId; |
| 3291 } | 3428 } |
| 3292 | 3429 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3325 already_disabled(false), | 3462 already_disabled(false), |
| 3326 extension(extension) {} | 3463 extension(extension) {} |
| 3327 | 3464 |
| 3328 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3465 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
| 3329 const Extension* extension, | 3466 const Extension* extension, |
| 3330 const ExtensionPermissionSet* permissions, | 3467 const ExtensionPermissionSet* permissions, |
| 3331 Reason reason) | 3468 Reason reason) |
| 3332 : reason(reason), | 3469 : reason(reason), |
| 3333 extension(extension), | 3470 extension(extension), |
| 3334 permissions(permissions) {} | 3471 permissions(permissions) {} |
| OLD | NEW |