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

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