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

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

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

Powered by Google App Engine
This is Rietveld 408576698