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

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: Updated for the most recent versions of chrome/common/extensions/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
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 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 utf8_error); 326 utf8_error);
327 } 327 }
328 328
329 scoped_refptr<Extension> Extension::Create(const FilePath& path, 329 scoped_refptr<Extension> Extension::Create(const FilePath& path,
330 Location location, 330 Location location,
331 const DictionaryValue& value, 331 const DictionaryValue& value,
332 int flags, 332 int flags,
333 const std::string& explicit_id, 333 const std::string& explicit_id,
334 std::string* utf8_error) { 334 std::string* utf8_error) {
335 DCHECK(utf8_error); 335 DCHECK(utf8_error);
336
337 string16 error; 336 string16 error;
338 scoped_ptr<extensions::Manifest> manifest( 337 scoped_ptr<extensions::Manifest> manifest(
339 new extensions::Manifest( 338 new extensions::Manifest(
340 location, 339 location,
341 scoped_ptr<DictionaryValue>(value.DeepCopy()))); 340 scoped_ptr<DictionaryValue>(value.DeepCopy())));
342 341
343 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error) || 342 if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error) ||
344 !manifest->ValidateManifest(&error)) { 343 !manifest->ValidateManifest(&error)) {
345 *utf8_error = UTF16ToUTF8(error); 344 *utf8_error = UTF16ToUTF8(error);
346 return NULL; 345 return NULL;
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false)); 472 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
474 473
475 return ret_val; 474 return ret_val;
476 } 475 }
477 476
478 bool Extension::is_platform_app() const { 477 bool Extension::is_platform_app() const {
479 return manifest_->IsPlatformApp(); 478 return manifest_->IsPlatformApp();
480 } 479 }
481 480
482 bool Extension::is_hosted_app() const { 481 bool Extension::is_hosted_app() const {
483 return manifest()->IsHostedApp(); 482 return manifest()->IsHostedApp();
484 } 483 }
485 484
486 bool Extension::is_packaged_app() const { 485 bool Extension::is_packaged_app() const {
487 return manifest()->IsPackagedApp(); 486 return manifest()->IsPackagedApp();
488 } 487 }
489 488
490 bool Extension::is_theme() const { 489 bool Extension::is_theme() const {
491 return manifest()->IsTheme(); 490 return manifest()->IsTheme();
492 } 491 }
493 492
494 GURL Extension::GetBackgroundURL() const { 493 GURL Extension::GetBackgroundURL() const {
495 if (!background_scripts_.empty()) { 494 if (!background_scripts_.empty()) {
496 return GetResourceURL( 495 return GetResourceURL(
497 extension_filenames::kGeneratedBackgroundPageFilename); 496 extension_filenames::kGeneratedBackgroundPageFilename);
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 result->SetPopupUrl(ExtensionAction::kDefaultTabId, url); 884 result->SetPopupUrl(ExtensionAction::kDefaultTabId, url);
886 } else { 885 } else {
887 DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId)) 886 DCHECK(!result->HasPopup(ExtensionAction::kDefaultTabId))
888 << "Shouldn't be possible for the popup to be set."; 887 << "Shouldn't be possible for the popup to be set.";
889 } 888 }
890 } 889 }
891 890
892 return result.release(); 891 return result.release();
893 } 892 }
894 893
895 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlers( 894 bool Extension::LoadSharedFeatures(const int& flags,
895 string16* error) {
896 if (!LoadName(error))
897 return false;
898
899 if (manifest_->HasKey(keys::kDescription) && !LoadDescription(error))
Aaron Boodman 2012/02/29 20:38:25 If you put the check for the presence of the key i
Devlin 2012/03/02 17:31:04 Done.
900 return false;
901
902 if (!LoadVersion(error))
903 return false;
904
905 // Validate minimum Chrome version. We don't need to store this, since the
906 // extension is not valid if it is incorrect
907 if (manifest_->HasKey(keys::kMinimumChromeVersion) &&
908 !LoadMinimumChromeVersion(error))
Yoyo Zhou 2012/03/01 01:17:25 Maybe call this CheckMinimumChromeVersion instead,
Devlin 2012/03/02 17:31:04 Done.
909 return false;
910
911 extension_url_ = Extension::GetBaseURLFromExtensionId(id());
912
913 if (manifest_->HasKey(keys::kHomepageURL) && !LoadHomepageURL(error))
914 return false;
915
916 if (manifest_->HasKey(keys::kUpdateURL) && !LoadUpdateURL(error))
917 return false;
918
919 return true;
920 }
921
922 bool Extension::LoadName(string16* error) {
923 string16 localized_name;
924 if (!manifest_->GetString(keys::kName, &localized_name)) {
925 *error = ASCIIToUTF16(errors::kInvalidName);
926 return false;
927 }
928 base::i18n::AdjustStringForLocaleDirection(&localized_name);
929 name_ = UTF16ToUTF8(localized_name);
930 return true;
931 }
932
933 bool Extension::LoadDescription(string16* error) {
934 if (!manifest_->GetString(keys::kDescription,
935 &description_)) {
936 *error = ASCIIToUTF16(errors::kInvalidDescription);
937 return false;
938 }
939 return true;
940 }
941
942 bool Extension::LoadVersion(string16* error) {
943 std::string version_str;
944 if (!manifest_->GetString(keys::kVersion, &version_str)) {
945 *error = ASCIIToUTF16(errors::kInvalidVersion);
946 return false;
947 }
948 version_.reset(Version::GetVersionFromString(version_str));
949 if (!version_.get() ||
950 version_->components().size() > 4) {
951 *error = ASCIIToUTF16(errors::kInvalidVersion);
952 return false;
953 }
954 return true;
955 }
956
957 bool Extension::LoadMinimumChromeVersion(string16* error) {
958 std::string minimum_version_string;
959 if (!manifest_->GetString(keys::kMinimumChromeVersion,
960 &minimum_version_string)) {
Aaron Boodman 2012/02/29 20:38:25 +1 indent
Devlin 2012/03/02 17:31:04 Done.
961 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
962 return false;
963 }
964
965 scoped_ptr<Version> minimum_version(
966 Version::GetVersionFromString(minimum_version_string));
967 if (!minimum_version.get()) {
968 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
969 return false;
970 }
971
972 chrome::VersionInfo current_version_info;
973 if (!current_version_info.is_valid()) {
974 NOTREACHED();
975 return false;
976 }
977
978 scoped_ptr<Version> current_version(
979 Version::GetVersionFromString(current_version_info.Version()));
980 if (!current_version.get()) {
981 DCHECK(false);
982 return false;
983 }
984
985 if (current_version->CompareTo(*minimum_version) < 0) {
986 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
987 errors::kChromeVersionTooLow,
988 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
989 minimum_version_string);
990 return false;
991 }
992 return true;
993 }
994
995 bool Extension::LoadManifestVersion(string16* error) {
996 // Get the original value out of the dictionary so that we can validate it
997 // more strictly.
998 if (manifest_->value()->HasKey(keys::kManifestVersion)) {
999 int manifest_version = 1;
1000 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
1001 manifest_version < 1) {
1002 *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
1003 return false;
1004 }
1005 }
1006
1007 manifest_version_ = manifest_->GetManifestVersion();
1008 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
1009 manifest_version_ < kModernManifestVersion &&
1010 !CommandLine::ForCurrentProcess()->HasSwitch(
1011 switches::kAllowLegacyExtensionManifests)) {
1012 *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
1013 return false;
1014 }
1015
1016 return true;
1017 }
1018
1019 // static
1020 bool Extension::InitExtensionID(extensions::Manifest* manifest,
1021 const FilePath& path,
1022 const std::string& explicit_id,
1023 int creation_flags,
1024 string16* error) {
1025 if (!explicit_id.empty()) {
1026 manifest->set_extension_id(explicit_id);
1027 return true;
1028 }
1029
1030 if (manifest->HasKey(keys::kPublicKey)) {
1031 std::string public_key;
1032 std::string public_key_bytes;
1033 std::string extension_id;
1034 if (!manifest->GetString(keys::kPublicKey, &public_key) ||
1035 !ParsePEMKeyBytes(public_key, &public_key_bytes) ||
1036 !GenerateId(public_key_bytes, &extension_id)) {
1037 *error = ASCIIToUTF16(errors::kInvalidKey);
1038 return false;
1039 }
1040 manifest->set_extension_id(extension_id);
1041 return true;
1042 }
1043
1044 if (creation_flags & REQUIRE_KEY) {
1045 *error = ASCIIToUTF16(errors::kInvalidKey);
1046 return false;
1047 } else {
1048 // If there is a path, we generate the ID from it. This is useful for
1049 // development mode, because it keeps the ID stable across restarts and
1050 // reloading the extension.
1051 std::string extension_id = GenerateIdForPath(path);
1052 if (extension_id.empty()) {
1053 NOTREACHED() << "Could not create ID from path.";
1054 return false;
1055 }
1056 manifest->set_extension_id(extension_id);
1057 return true;
1058 }
1059 }
1060
1061 bool Extension::LoadHomepageURL(string16* error) {
1062 std::string tmp;
1063 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) {
1064 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1065 errors::kInvalidHomepageURL, "");
1066 return false;
1067 }
1068 homepage_url_ = GURL(tmp);
1069 if (!homepage_url_.is_valid() ||
1070 (!homepage_url_.SchemeIs("http") &&
1071 !homepage_url_.SchemeIs("https"))) {
1072 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1073 errors::kInvalidHomepageURL, tmp);
1074 return false;
1075 }
1076 return true;
1077 }
1078
1079 bool Extension::LoadUpdateURL(string16* error) {
1080 std::string tmp;
1081 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) {
1082 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1083 errors::kInvalidUpdateURL, "");
1084 return false;
1085 }
1086 update_url_ = GURL(tmp);
1087 if (!update_url_.is_valid() ||
1088 update_url_.has_ref()) {
1089 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1090 errors::kInvalidUpdateURL, tmp);
1091 return false;
1092 }
1093 return true;
1094 }
1095
1096 bool Extension::LoadExtensionFeatures(
1097 const int& flags,
1098 const ExtensionAPIPermissionSet& api_permissions,
1099 string16* error) {
1100 if (manifest_->HasKey(keys::kOptionsPage) &&
Yoyo Zhou 2012/03/01 01:17:25 As Aaron wrote, you can check for the presence of
Devlin 2012/03/02 17:31:04 Done.
1101 !LoadOptionsPage(error))
Yoyo Zhou 2012/03/01 01:17:25 unfortunately these aren't all exclusively extensi
Devlin 2012/03/02 17:31:04 Thanks! A while back, Aaron listed the ones he th
1102 return false;
1103
1104 if (manifest_->HasKey(keys::kDevToolsPage) &&
1105 !LoadDevToolsPage(error))
1106 return false;
1107
1108 if (manifest_->HasKey(keys::kInputComponents) &&
1109 !LoadInputComponents(api_permissions, error))
1110 return false;
1111
1112 if (manifest_->HasKey(keys::kConvertedFromUserScript))
1113 manifest_->GetBoolean(keys::kConvertedFromUserScript,
1114 &converted_from_user_script_);
Yoyo Zhou 2012/03/01 01:17:25 indent +1
Devlin 2012/03/02 17:31:04 Done.
1115
1116 if (manifest_->HasKey(keys::kIcons) && !LoadIcons(error))
1117 return false;
1118
1119 if (manifest_->HasKey(keys::kCommands) && !LoadCommands(error))
1120 return false;
1121
1122 if (manifest_->HasKey(keys::kPlugins) && !LoadPlugins(error))
1123 return false;
1124
1125 if (manifest_->HasKey(keys::kNaClModules) && !LoadNaClModules(error))
1126 return false;
1127
1128 if (manifest_->HasKey(keys::kContentScripts) &&
1129 !LoadContentScripts(flags, error))
1130 return false;
1131
1132 if (manifest_->HasKey(keys::kWebAccessibleResources) &&
1133 !LoadWebAccessibleResources(error))
1134 return false;
1135
1136 if (!LoadPageAction(error))
1137 return false;
1138
1139 if (manifest_->HasKey(keys::kBrowserAction) &&
1140 !LoadBrowserAction(error))
1141 return false;
1142
1143 if (manifest_->HasKey(keys::kFileBrowserHandlers) &&
1144 !LoadFileBrowserHandlers(error))
1145 return false;
1146
1147 if (manifest_->HasKey(keys::kChromeURLOverrides) &&
1148 !LoadChromeURLOverrides(error))
1149 return false;
1150
1151 if (manifest_->HasKey(keys::kOmnibox) && !LoadOmnibox(error))
1152 return false;
1153
1154 if (manifest_->HasKey(keys::kTtsEngine) &&
1155 !LoadTextToSpeechVoices(error))
1156 return false;
1157
1158 if (!LoadWebIntentServices(error))
1159 return false;
1160
1161 // These are not actually persisted (they're only used by the store), but
1162 // still validated.
1163 if (manifest_->HasKey(keys::kRequirements) &&
1164 !LoadRequirements(error))
1165 return false;
1166
1167 if (manifest_->HasKey(keys::kDefaultLocale) &&
1168 !LoadDefaultLocale(error))
1169 return false;
1170
1171 // Defaults to false.
Yoyo Zhou 2012/03/01 01:17:25 Comments like this seem like they should be in the
Devlin 2012/03/02 17:31:04 Done.
1172 if (manifest_->HasKey(keys::kOfflineEnabled) &&
1173 !LoadOfflineEnabled(error))
1174 return false;
1175
1176 // Apps default to split mode, extensions default to spanning.
1177 incognito_split_mode_ = is_app();
Yoyo Zhou 2012/03/01 01:17:25 Should be inside LoadIncognito, which I would rena
Devlin 2012/03/02 17:31:04 Done. I was debating making it LoadIncognitoMode
1178 if (manifest_->HasKey(keys::kIncognito) && !LoadIncognito(error))
1179 return false;
1180
1181 if (!LoadBackgroundScripts(error))
1182 return false;
1183
1184 if (!LoadBackgroundPage(api_permissions, error))
1185 return false;
1186
1187 if (!LoadBackgroundPersistent(api_permissions, error))
1188 return false;
1189
1190 if (!LoadContentSecurityPolicy(error))
1191 return false;
1192
1193 return true;
1194 }
1195
1196 bool Extension::LoadOptionsPage(string16* error) {
1197 std::string options_str;
1198 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) {
1199 *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
1200 return false;
1201 }
1202
1203 if (is_hosted_app()) {
1204 // hosted apps require an absolute URL.
1205 GURL options_url(options_str);
1206 if (!options_url.is_valid() ||
1207 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) {
1208 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
1209 return false;
1210 }
1211 options_url_ = options_url;
1212 } else {
1213 GURL absolute(options_str);
1214 if (absolute.is_valid()) {
1215 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
1216 return false;
1217 }
1218 options_url_ = GetResourceURL(options_str);
1219 if (!options_url_.is_valid()) {
1220 *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
1221 return false;
1222 }
1223 }
1224
1225 return true;
1226 }
1227
1228 bool Extension::LoadDevToolsPage(string16* error) {
1229 std::string devtools_str;
1230 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) {
1231 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage);
1232 return false;
1233 }
1234 devtools_url_ = GetResourceURL(devtools_str);
1235 return true;
1236 }
1237
1238 bool Extension::LoadInputComponents(
1239 const ExtensionAPIPermissionSet& api_permissions,
1240 string16* error) {
1241 ListValue* list_value = NULL;
1242 if (!manifest_->GetList(keys::kInputComponents, &list_value)) {
1243 *error = ASCIIToUTF16(errors::kInvalidInputComponents);
1244 return false;
1245 }
1246
1247 for (size_t i = 0; i < list_value->GetSize(); ++i) {
1248 DictionaryValue* module_value = NULL;
1249 std::string name_str;
1250 InputComponentType type;
1251 std::string id_str;
1252 std::string description_str;
1253 std::string language_str;
1254 std::set<std::string> layouts;
1255 std::string shortcut_keycode_str;
1256 bool shortcut_alt = false;
1257 bool shortcut_ctrl = false;
1258 bool shortcut_shift = false;
1259
1260 if (!list_value->GetDictionary(i, &module_value)) {
1261 *error = ASCIIToUTF16(errors::kInvalidInputComponents);
1262 return false;
1263 }
1264
1265 // Get input_components[i].name.
1266 if (!module_value->GetString(keys::kName, &name_str)) {
1267 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1268 errors::kInvalidInputComponentName, base::IntToString(i));
1269 return false;
1270 }
1271
1272 // Get input_components[i].type.
1273 std::string type_str;
1274 if (module_value->GetString(keys::kType, &type_str)) {
1275 if (type_str == "ime") {
1276 type = INPUT_COMPONENT_TYPE_IME;
1277 } else if (type_str == "virtual_keyboard") {
1278 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) {
1279 // Virtual Keyboards require the experimental flag.
1280 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1281 errors::kInvalidInputComponentType, base::IntToString(i));
1282 return false;
1283 }
1284 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD;
1285 } else {
1286 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1287 errors::kInvalidInputComponentType, base::IntToString(i));
1288 return false;
1289 }
1290 } else {
1291 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1292 errors::kInvalidInputComponentType, base::IntToString(i));
1293 return false;
1294 }
1295
1296 // Get input_components[i].id.
1297 if (!module_value->GetString(keys::kId, &id_str)) {
1298 id_str = "";
1299 }
1300
1301 // Get input_components[i].description.
1302 if (!module_value->GetString(keys::kDescription, &description_str)) {
1303 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1304 errors::kInvalidInputComponentDescription, base::IntToString(i));
1305 return false;
1306 }
1307 // Get input_components[i].language.
1308 if (!module_value->GetString(keys::kLanguage, &language_str)) {
1309 language_str = "";
1310 }
1311
1312 // Get input_components[i].layouts.
1313 ListValue* layouts_value = NULL;
1314 if (!module_value->GetList(keys::kLayouts, &layouts_value)) {
1315 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts);
1316 return false;
1317 }
1318
1319 for (size_t j = 0; j < layouts_value->GetSize(); ++j) {
1320 std::string layout_name_str;
1321 if (!layouts_value->GetString(j, &layout_name_str)) {
1322 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1323 errors::kInvalidInputComponentLayoutName, base::IntToString(i),
1324 base::IntToString(j));
1325 return false;
1326 }
1327 layouts.insert(layout_name_str);
1328 }
1329
1330 if (module_value->HasKey(keys::kShortcutKey)) {
1331 DictionaryValue* shortcut_value = NULL;
1332 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) {
1333 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1334 errors::kInvalidInputComponentShortcutKey, base::IntToString(i));
1335 return false;
1336 }
1337
1338 // Get input_components[i].shortcut_keycode.
1339 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
1340 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1341 errors::kInvalidInputComponentShortcutKeycode,
1342 base::IntToString(i));
1343 return false;
1344 }
1345
1346 // Get input_components[i].shortcut_alt.
1347 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
1348 shortcut_alt = false;
1349 }
1350
1351 // Get input_components[i].shortcut_ctrl.
1352 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
1353 shortcut_ctrl = false;
1354 }
1355
1356 // Get input_components[i].shortcut_shift.
1357 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
1358 shortcut_shift = false;
1359 }
1360 }
1361
1362 input_components_.push_back(InputComponentInfo());
1363 input_components_.back().name = name_str;
1364 input_components_.back().type = type;
1365 input_components_.back().id = id_str;
1366 input_components_.back().description = description_str;
1367 input_components_.back().language = language_str;
1368 input_components_.back().layouts.insert(layouts.begin(), layouts.end());
1369 input_components_.back().shortcut_keycode = shortcut_keycode_str;
1370 input_components_.back().shortcut_alt = shortcut_alt;
1371 input_components_.back().shortcut_ctrl = shortcut_ctrl;
1372 input_components_.back().shortcut_shift = shortcut_shift;
1373 }
1374
1375 return true;
1376 }
1377 bool Extension::LoadIcons(string16* error) {
1378 DictionaryValue* icons_value = NULL;
1379 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) {
1380 *error = ASCIIToUTF16(errors::kInvalidIcons);
1381 return false;
1382 }
1383
1384 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) {
1385 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]);
1386 if (icons_value->HasKey(key)) {
1387 std::string icon_path;
1388 if (!icons_value->GetString(key, &icon_path)) {
1389 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1390 errors::kInvalidIconPath, key);
1391 return false;
1392 }
1393
1394 if (!icon_path.empty() && icon_path[0] == '/')
1395 icon_path = icon_path.substr(1);
1396
1397 if (icon_path.empty()) {
1398 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1399 errors::kInvalidIconPath, key);
1400 return false;
1401 }
1402 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path);
1403 }
1404 }
1405 return true;
1406 }
1407
1408 bool Extension::LoadCommands(string16* error) {
1409 if (manifest_->HasKey(keys::kCommands)) {
1410 DictionaryValue* commands = NULL;
1411 if (!manifest_->GetDictionary(keys::kCommands, &commands)) {
1412 *error = ASCIIToUTF16(errors::kInvalidCommandsKey);
1413 return false;
1414 }
1415
1416 int command_index = 0;
1417 for (DictionaryValue::key_iterator iter = commands->begin_keys();
1418 iter != commands->end_keys(); ++iter) {
1419 ++command_index;
1420
1421 DictionaryValue* command = NULL;
1422 if (!commands->GetDictionary(*iter, &command)) {
1423 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1424 errors::kInvalidKeyBindingDictionary,
1425 base::IntToString(command_index));
1426 return false;
1427 }
1428
1429 ExtensionKeybinding binding;
1430 if (!binding.Parse(command, *iter, command_index, error))
1431 return false; // |error| already set.
1432
1433 commands_.push_back(binding);
1434 }
1435 }
1436 return true;
1437 }
1438
1439 bool Extension::LoadPlugins(string16* error) {
1440 ListValue* list_value = NULL;
1441 if (!manifest_->GetList(keys::kPlugins, &list_value)) {
1442 *error = ASCIIToUTF16(errors::kInvalidPlugins);
1443 return false;
1444 }
1445
1446 for (size_t i = 0; i < list_value->GetSize(); ++i) {
1447 DictionaryValue* plugin_value = NULL;
1448 std::string path_str;
1449 bool is_public = false;
1450 if (!list_value->GetDictionary(i, &plugin_value)) {
1451 *error = ASCIIToUTF16(errors::kInvalidPlugins);
1452 return false;
1453 }
1454 // Get plugins[i].path.
1455 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
1456 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1457 errors::kInvalidPluginsPath, base::IntToString(i));
1458 return false;
1459 }
1460
1461 // Get plugins[i].content (optional).
1462 if (plugin_value->HasKey(keys::kPluginsPublic)) {
1463 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
1464 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1465 errors::kInvalidPluginsPublic, base::IntToString(i));
1466 return false;
1467 }
1468 }
1469
1470 // We don't allow extension plugins to run on Chrome OS. We still
1471 // parse the manifest entry so that error messages are consistently
1472 // displayed across platforms.
1473 #if !defined(OS_CHROMEOS)
1474 plugins_.push_back(PluginInfo());
1475 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str));
1476 plugins_.back().is_public = is_public;
1477 #endif
1478 }
1479 return true;
1480 }
1481
1482 bool Extension::LoadNaClModules(string16* error) {
1483 ListValue* list_value = NULL;
1484 if (!manifest_->GetList(keys::kNaClModules, &list_value)) {
1485 *error = ASCIIToUTF16(errors::kInvalidNaClModules);
1486 return false;
1487 }
1488
1489 for (size_t i = 0; i < list_value->GetSize(); ++i) {
1490 DictionaryValue* module_value = NULL;
1491 std::string path_str;
1492 std::string mime_type;
1493
1494 if (!list_value->GetDictionary(i, &module_value)) {
1495 *error = ASCIIToUTF16(errors::kInvalidNaClModules);
1496 return false;
1497 }
1498
1499 // Get nacl_modules[i].path.
1500 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
1501 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1502 errors::kInvalidNaClModulesPath, base::IntToString(i));
1503 return false;
1504 }
1505
1506 // Get nacl_modules[i].mime_type.
1507 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
1508 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1509 errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
1510 return false;
1511 }
1512
1513 nacl_modules_.push_back(NaClModuleInfo());
1514 nacl_modules_.back().url = GetResourceURL(path_str);
1515 nacl_modules_.back().mime_type = mime_type;
1516 }
1517
1518 return true;
1519 }
1520
1521 bool Extension::LoadContentScripts(const int& flags,
1522 string16* error) {
1523 ListValue* list_value;
1524 if (!manifest_->GetList(keys::kContentScripts, &list_value)) {
1525 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList);
1526 return false;
1527 }
1528
1529 for (size_t i = 0; i < list_value->GetSize(); ++i) {
1530 DictionaryValue* content_script = NULL;
1531 if (!list_value->GetDictionary(i, &content_script)) {
1532 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1533 errors::kInvalidContentScript, base::IntToString(i));
1534 return false;
1535 }
1536
1537 UserScript script;
1538 if (!LoadUserScriptHelper(content_script, i, flags, error, &script))
1539 return false; // Failed to parse script context definition.
1540 script.set_extension_id(id());
1541 if (converted_from_user_script_) {
1542 script.set_emulate_greasemonkey(true);
1543 script.set_match_all_frames(true); // Greasemonkey matches all frames.
1544 }
1545 content_scripts_.push_back(script);
1546 }
1547 return true;
1548 }
1549
1550 bool Extension::LoadWebAccessibleResources(string16* error) {
1551 ListValue* list_value;
1552 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) {
1553 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList);
1554 return false;
1555 }
1556 for (size_t i = 0; i < list_value->GetSize(); ++i) {
1557 std::string relative_path;
1558 if (!list_value->GetString(i, &relative_path)) {
1559 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1560 errors::kInvalidWebAccessibleResource, base::IntToString(i));
1561 return false;
1562 }
1563 if (relative_path[0] != '/')
1564 relative_path = '/' + relative_path;
1565 web_accessible_resources_.insert(relative_path);
1566 }
1567
1568 return true;
1569 }
1570
1571 bool Extension::LoadPageAction(string16* error) {
1572 DictionaryValue* page_action_value = NULL;
1573
1574 if (manifest_->HasKey(keys::kPageActions)) {
1575 ListValue* list_value = NULL;
1576 if (!manifest_->GetList(keys::kPageActions, &list_value)) {
1577 *error = ASCIIToUTF16(errors::kInvalidPageActionsList);
1578 return false;
1579 }
1580
1581 size_t list_value_length = list_value->GetSize();
1582
1583 if (list_value_length == 0u) {
1584 // A list with zero items is allowed, and is equivalent to not having
1585 // a page_actions key in the manifest. Don't set |page_action_value|.
1586 } else if (list_value_length == 1u) {
1587 if (!list_value->GetDictionary(0, &page_action_value)) {
1588 *error = ASCIIToUTF16(errors::kInvalidPageAction);
1589 return false;
1590 }
1591 } else { // list_value_length > 1u.
1592 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize);
1593 return false;
1594 }
1595 } else if (manifest_->HasKey(keys::kPageAction)) {
1596 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) {
1597 *error = ASCIIToUTF16(errors::kInvalidPageAction);
1598 return false;
1599 }
1600 }
1601
1602 // If page_action_value is not NULL, then there was a valid page action.
1603 if (page_action_value) {
1604 page_action_.reset(
1605 LoadExtensionActionHelper(page_action_value, error));
1606 if (!page_action_.get())
1607 return false; // Failed to parse page action definition.
1608 }
1609
1610 return true;
1611 }
1612
1613 bool Extension::LoadBrowserAction(string16* error) {
1614 DictionaryValue* browser_action_value = NULL;
1615 if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) {
1616 *error = ASCIIToUTF16(errors::kInvalidBrowserAction);
1617 return false;
1618 }
1619
1620 browser_action_.reset(
1621 LoadExtensionActionHelper(browser_action_value, error));
1622 if (!browser_action_.get())
1623 return false; // Failed to parse browser action definition.
1624 return true;
1625 }
1626
1627 bool Extension::LoadFileBrowserHandlers(string16* error) {
1628 ListValue* file_browser_handlers_value = NULL;
1629 if (!manifest_->GetList(keys::kFileBrowserHandlers,
1630 &file_browser_handlers_value)) {
1631 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
1632 return false;
1633 }
1634 file_browser_handlers_.reset(
1635 LoadFileBrowserHandlersHelper(file_browser_handlers_value, error));
1636 if (!file_browser_handlers_.get())
1637 return false; // Failed to parse file browser actions definition.
1638 return true;
1639 }
1640
1641 Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlersHelper(
896 const ListValue* extension_actions, string16* error) { 1642 const ListValue* extension_actions, string16* error) {
897 scoped_ptr<FileBrowserHandlerList> result( 1643 scoped_ptr<FileBrowserHandlerList> result(
898 new FileBrowserHandlerList()); 1644 new FileBrowserHandlerList());
899 for (ListValue::const_iterator iter = extension_actions->begin(); 1645 for (ListValue::const_iterator iter = extension_actions->begin();
900 iter != extension_actions->end(); 1646 iter != extension_actions->end();
901 ++iter) { 1647 ++iter) {
902 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) { 1648 if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
903 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); 1649 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
904 return NULL; 1650 return NULL;
905 } 1651 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 default_icon.empty()) { 1725 default_icon.empty()) {
980 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); 1726 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
981 return NULL; 1727 return NULL;
982 } 1728 }
983 result->set_icon_path(default_icon); 1729 result->set_icon_path(default_icon);
984 } 1730 }
985 1731
986 return result.release(); 1732 return result.release();
987 } 1733 }
988 1734
989 bool Extension::LoadExtent(const char* key, 1735 bool Extension::LoadChromeURLOverrides(string16* error) {
990 URLPatternSet* extent, 1736 DictionaryValue* overrides = NULL;
991 const char* list_error, 1737 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) {
992 const char* value_error, 1738 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
993 string16* error) { 1739 return false;
994 Value* temp = NULL; 1740 }
995 if (!manifest_->Get(key, &temp)) 1741
996 return true; 1742 // Validate that the overrides are all strings
997 1743 for (DictionaryValue::key_iterator iter = overrides->begin_keys();
998 if (temp->GetType() != Value::TYPE_LIST) { 1744 iter != overrides->end_keys(); ++iter) {
999 *error = ASCIIToUTF16(list_error); 1745 std::string page = *iter;
1000 return false; 1746 std::string val;
1001 } 1747 // Restrict override pages to a list of supported URLs.
1002 1748 if ((page != chrome::kChromeUINewTabHost &&
1003 ListValue* pattern_list = static_cast<ListValue*>(temp); 1749 #if defined(USE_VIRTUAL_KEYBOARD)
1004 for (size_t i = 0; i < pattern_list->GetSize(); ++i) { 1750 page != chrome::kChromeUIKeyboardHost &&
1005 std::string pattern_string; 1751 #endif
1006 if (!pattern_list->GetString(i, &pattern_string)) { 1752 #if defined(OS_CHROMEOS)
1007 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(value_error, 1753 page != chrome::kChromeUIActivationMessageHost &&
1008 base::UintToString(i), 1754 #endif
1009 errors::kExpectString); 1755 page != chrome::kChromeUIBookmarksHost &&
1010 return false; 1756 page != chrome::kChromeUIHistoryHost
1011 } 1757 #if defined(FILE_MANAGER_EXTENSION)
1012 1758 &&
1013 URLPattern pattern(kValidWebExtentSchemes); 1759 !(location() == COMPONENT &&
1014 URLPattern::ParseResult parse_result = pattern.Parse(pattern_string); 1760 page == chrome::kChromeUIFileManagerHost)
1015 if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) { 1761 #endif
1016 pattern_string += "/"; 1762 ) ||
1017 parse_result = pattern.Parse(pattern_string); 1763 !overrides->GetStringWithoutPathExpansion(*iter, &val)) {
1018 } 1764 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
1019 1765 return false;
1020 if (parse_result != URLPattern::PARSE_SUCCESS) { 1766 }
1021 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1767 // Replace the entry with a fully qualified chrome-extension:// URL.
1022 value_error, 1768 chrome_url_overrides_[page] = GetResourceURL(val);
1023 base::UintToString(i), 1769 }
1024 URLPattern::GetParseResultString(parse_result)); 1770
1025 return false; 1771 // An extension may override at most one page.
1026 } 1772 if (overrides->size() > 1) {
1027 1773 *error = ASCIIToUTF16(errors::kMultipleOverrides);
1028 // Do not allow authors to claim "<all_urls>". 1774 return false;
1029 if (pattern.match_all_urls()) { 1775 }
1030 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1776
1031 value_error, 1777 return true;
1032 base::UintToString(i), 1778 }
1033 errors::kCannotClaimAllURLsInExtent); 1779
1034 return false; 1780 bool Extension::LoadOmnibox(string16* error) {
1035 } 1781 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
1036 1782 omnibox_keyword_.empty()) {
1037 // Do not allow authors to claim "*" for host. 1783 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword);
1038 if (pattern.host().empty()) { 1784 return false;
1039 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1785 }
1040 value_error, 1786 return true;
1041 base::UintToString(i), 1787 }
1042 errors::kCannotClaimAllHostsInExtent); 1788
1043 return false; 1789 bool Extension::LoadTextToSpeechVoices(string16* error) {
1044 } 1790 DictionaryValue* tts_dict = NULL;
1045 1791 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) {
1046 // We do not allow authors to put wildcards in their paths. Instead, we 1792 *error = ASCIIToUTF16(errors::kInvalidTts);
1047 // imply one at the end. 1793 return false;
1048 if (pattern.path().find('*') != std::string::npos) { 1794 }
1049 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1795
1050 value_error, 1796 if (tts_dict->HasKey(keys::kTtsVoices)) {
1051 base::UintToString(i), 1797 ListValue* tts_voices = NULL;
1052 errors::kNoWildCardsInPaths); 1798 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
1053 return false; 1799 *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
1054 } 1800 return false;
1055 pattern.SetPath(pattern.path() + '*'); 1801 }
1056 1802
1057 extent->AddPattern(pattern); 1803 for (size_t i = 0; i < tts_voices->GetSize(); i++) {
1058 } 1804 DictionaryValue* one_tts_voice = NULL;
1059 1805 if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
1060 return true; 1806 *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
1061 } 1807 return false;
1062 1808 }
1063 bool Extension::LoadLaunchURL(string16* error) { 1809
1064 Value* temp = NULL; 1810 TtsVoice voice_data;
1065 1811 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
1066 // launch URL can be either local (to chrome-extension:// root) or an absolute 1812 if (!one_tts_voice->GetString(
1067 // web URL. 1813 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
1068 if (manifest_->Get(keys::kLaunchLocalPath, &temp)) { 1814 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName);
1069 if (manifest_->Get(keys::kLaunchWebURL, NULL)) { 1815 return false;
1070 *error = ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive); 1816 }
1071 return false; 1817 }
1072 } 1818 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) {
1073 1819 if (!one_tts_voice->GetString(
1074 if (manifest_->Get(keys::kWebURLs, NULL)) { 1820 keys::kTtsVoicesLang, &voice_data.lang) ||
1075 *error = ASCIIToUTF16(errors::kLaunchPathAndExtentAreExclusive); 1821 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) {
1076 return false; 1822 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang);
1077 } 1823 return false;
1078 1824 }
1079 std::string launch_path; 1825 }
1080 if (!temp->GetAsString(&launch_path)) { 1826 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
1081 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1827 if (!one_tts_voice->GetString(
1082 errors::kInvalidLaunchValue, 1828 keys::kTtsVoicesGender, &voice_data.gender) ||
1083 keys::kLaunchLocalPath); 1829 (voice_data.gender != keys::kTtsGenderMale &&
1084 return false; 1830 voice_data.gender != keys::kTtsGenderFemale)) {
1085 } 1831 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender);
1086 1832 return false;
1087 // Ensure the launch path is a valid relative URL. 1833 }
1088 GURL resolved = url().Resolve(launch_path); 1834 }
1089 if (!resolved.is_valid() || resolved.GetOrigin() != url()) { 1835 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) {
1090 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1836 ListValue* event_types_list;
1091 errors::kInvalidLaunchValue, 1837 if (!one_tts_voice->GetList(
1092 keys::kLaunchLocalPath); 1838 keys::kTtsVoicesEventTypes, &event_types_list)) {
1093 return false; 1839 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1094 } 1840 return false;
1095 1841 }
1096 launch_local_path_ = launch_path; 1842 for (size_t i = 0; i < event_types_list->GetSize(); i++) {
1097 } else if (manifest_->Get(keys::kLaunchWebURL, &temp)) { 1843 std::string event_type;
1098 std::string launch_url; 1844 if (!event_types_list->GetString(i, &event_type)) {
1099 if (!temp->GetAsString(&launch_url)) { 1845 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1100 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1846 return false;
1101 errors::kInvalidLaunchValue, 1847 }
1102 keys::kLaunchWebURL); 1848 if (event_type != keys::kTtsVoicesEventTypeEnd &&
1103 return false; 1849 event_type != keys::kTtsVoicesEventTypeError &&
1104 } 1850 event_type != keys::kTtsVoicesEventTypeMarker &&
1105 1851 event_type != keys::kTtsVoicesEventTypeSentence &&
1106 // Ensure the launch URL is a valid absolute URL and web extent scheme. 1852 event_type != keys::kTtsVoicesEventTypeStart &&
1107 GURL url(launch_url); 1853 event_type != keys::kTtsVoicesEventTypeWord) {
1108 URLPattern pattern(kValidWebExtentSchemes); 1854 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1109 if (!url.is_valid() || !pattern.SetScheme(url.scheme())) { 1855 return false;
1110 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1856 }
1111 errors::kInvalidLaunchValue, 1857 if (voice_data.event_types.find(event_type) !=
1112 keys::kLaunchWebURL); 1858 voice_data.event_types.end()) {
1113 return false; 1859 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1114 } 1860 return false;
1115 1861 }
1116 launch_web_url_ = launch_url; 1862 voice_data.event_types.insert(event_type);
1117 } else if (is_app()) { 1863 }
1118 *error = ASCIIToUTF16(errors::kLaunchURLRequired); 1864 }
1119 return false; 1865
1120 } 1866 tts_voices_.push_back(voice_data);
1121
1122 // If there is no extent, we default the extent based on the launch URL.
1123 if (web_extent().is_empty() && !launch_web_url().empty()) {
1124 GURL launch_url(launch_web_url());
1125 URLPattern pattern(kValidWebExtentSchemes);
1126 if (!pattern.SetScheme("*")) {
1127 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1128 errors::kInvalidLaunchValue,
1129 keys::kLaunchWebURL);
1130 return false;
1131 }
1132 pattern.SetHost(launch_url.host());
1133 pattern.SetPath("/*");
1134 extent_.AddPattern(pattern);
1135 }
1136
1137 // In order for the --apps-gallery-url switch to work with the gallery
1138 // process isolation, we must insert any provided value into the component
1139 // app's launch url and web extent.
1140 if (id() == extension_misc::kWebStoreAppId) {
1141 std::string gallery_url_str = CommandLine::ForCurrentProcess()->
1142 GetSwitchValueASCII(switches::kAppsGalleryURL);
1143
1144 // Empty string means option was not used.
1145 if (!gallery_url_str.empty()) {
1146 GURL gallery_url(gallery_url_str);
1147 OverrideLaunchUrl(gallery_url);
1148 }
1149 } else if (id() == extension_misc::kCloudPrintAppId) {
1150 // In order for the --cloud-print-service switch to work, we must update
1151 // the launch URL and web extent.
1152 // TODO(sanjeevr): Ideally we want to use CloudPrintURL here but that is
1153 // currently under chrome/browser.
1154 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1155 GURL cloud_print_service_url = GURL(command_line.GetSwitchValueASCII(
1156 switches::kCloudPrintServiceURL));
1157 if (!cloud_print_service_url.is_empty()) {
1158 std::string path(
1159 cloud_print_service_url.path() + "/enable_chrome_connector");
1160 GURL::Replacements replacements;
1161 replacements.SetPathStr(path);
1162 GURL cloud_print_enable_connector_url =
1163 cloud_print_service_url.ReplaceComponents(replacements);
1164 OverrideLaunchUrl(cloud_print_enable_connector_url);
1165 }
1166 }
1167 return true;
1168 }
1169
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) {
1195 Value* temp = NULL;
1196 if (!manifest_->Get(keys::kLaunchContainer, &temp))
1197 return true;
1198
1199 std::string launch_container_string;
1200 if (!temp->GetAsString(&launch_container_string)) {
1201 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
1202 return false;
1203 }
1204
1205 if (launch_container_string == values::kLaunchContainerShell) {
1206 launch_container_ = extension_misc::LAUNCH_SHELL;
1207 } else if (launch_container_string == values::kLaunchContainerPanel) {
1208 launch_container_ = extension_misc::LAUNCH_PANEL;
1209 } else if (launch_container_string == values::kLaunchContainerTab) {
1210 launch_container_ = extension_misc::LAUNCH_TAB;
1211 } else {
1212 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
1213 return false;
1214 }
1215
1216 bool can_specify_initial_size =
1217 launch_container() == extension_misc::LAUNCH_PANEL ||
1218 launch_container() == extension_misc::LAUNCH_WINDOW ||
1219 launch_container() == extension_misc::LAUNCH_SHELL;
1220
1221 // Validate the container width if present.
1222 if (!ReadLaunchDimension(manifest_,
1223 keys::kLaunchWidth,
1224 &launch_width_,
1225 can_specify_initial_size,
1226 error))
1227 return false;
1228
1229 // Validate container height if present.
1230 if (!ReadLaunchDimension(manifest_,
1231 keys::kLaunchHeight,
1232 &launch_height_,
1233 can_specify_initial_size,
1234 error))
1235 return false;
1236
1237 bool can_specify_size_range =
1238 launch_container() == extension_misc::LAUNCH_SHELL;
1239
1240 // Validate min size if present.
1241 if (!ReadLaunchDimension(manifest_,
1242 keys::kLaunchMinWidth,
1243 &launch_min_width_,
1244 can_specify_size_range,
1245 error))
1246 return false;
1247 if (!ReadLaunchDimension(manifest_,
1248 keys::kLaunchMinHeight,
1249 &launch_min_height_,
1250 can_specify_size_range,
1251 error))
1252 return false;
1253
1254 if (launch_container() == extension_misc::LAUNCH_SHELL) {
1255 if (!manifest_->Get(keys::kLaunchWidth, &temp)) {
1256 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1257 errors::kInvalidLaunchValue,
1258 keys::kLaunchWidth);
1259 return false;
1260 }
1261 if (!manifest_->Get(keys::kLaunchHeight, &temp)) {
1262 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1263 errors::kInvalidLaunchValue,
1264 keys::kLaunchHeight);
1265 return false;
1266 }
1267 }
1268
1269 return true;
1270 }
1271
1272 bool Extension::LoadAppIsolation(string16* error) {
1273 Value* temp = NULL;
1274 if (!manifest_->Get(keys::kIsolation, &temp))
1275 return true;
1276
1277 if (temp->GetType() != Value::TYPE_LIST) {
1278 *error = ASCIIToUTF16(errors::kInvalidIsolation);
1279 return false;
1280 }
1281
1282 ListValue* isolation_list = static_cast<ListValue*>(temp);
1283 for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
1284 std::string isolation_string;
1285 if (!isolation_list->GetString(i, &isolation_string)) {
1286 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1287 errors::kInvalidIsolationValue,
1288 base::UintToString(i));
1289 return false;
1290 }
1291
1292 // Check for isolated storage.
1293 if (isolation_string == values::kIsolatedStorage) {
1294 is_storage_isolated_ = true;
1295 } else {
1296 DLOG(WARNING) << "Did not recognize isolation type: "
1297 << isolation_string;
1298 } 1867 }
1299 } 1868 }
1300 return true; 1869 return true;
1301 } 1870 }
1302 1871
1303 bool Extension::LoadWebIntentServices(string16* error) { 1872 bool Extension::LoadWebIntentServices(string16* error) {
1304 DCHECK(error); 1873 DCHECK(error);
1305 1874
1306 if (!manifest_->HasKey(keys::kIntents)) 1875 if (!manifest_->HasKey(keys::kIntents))
1307 return true; 1876 return true;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1387 errors::kInvalidIntentTypeElement, *iter, 1956 errors::kInvalidIntentTypeElement, *iter,
1388 std::string(base::IntToString(i))); 1957 std::string(base::IntToString(i)));
1389 return false; 1958 return false;
1390 } 1959 }
1391 intents_services_.push_back(service); 1960 intents_services_.push_back(service);
1392 } 1961 }
1393 } 1962 }
1394 return true; 1963 return true;
1395 } 1964 }
1396 1965
1966 bool Extension::LoadRequirements(string16* error) {
1967 DictionaryValue* requirements_value = NULL;
1968 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) {
1969 *error = ASCIIToUTF16(errors::kInvalidRequirements);
1970 return false;
1971 }
1972
1973 for (DictionaryValue::key_iterator it = requirements_value->begin_keys();
1974 it != requirements_value->end_keys(); ++it) {
1975 DictionaryValue* requirement_value;
1976 if (!requirements_value->GetDictionaryWithoutPathExpansion(
1977 *it, &requirement_value)) {
1978 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1979 errors::kInvalidRequirement, *it);
1980 return false;
1981 }
1982 }
1983 return true;
1984 }
1985
1986 bool Extension::LoadDefaultLocale(string16* error) {
1987 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) ||
1988 !l10n_util::IsValidLocaleSyntax(default_locale_)) {
1989 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale);
1990 return false;
1991 }
1992 return true;
1993 }
1994
1995 bool Extension::LoadOfflineEnabled(string16* error) {
1996 if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
1997 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled);
1998 return false;
1999 }
2000 return true;
2001 }
2002
2003 bool Extension::LoadIncognito(string16* error) {
2004 std::string value;
2005 if (!manifest_->GetString(keys::kIncognito, &value)) {
2006 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
2007 return false;
2008 }
2009 if (value == values::kIncognitoSpanning) {
2010 incognito_split_mode_ = false;
2011 } else if (value == values::kIncognitoSplit) {
2012 incognito_split_mode_ = true;
2013 } else {
2014 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
2015 return false;
2016 }
2017 return true;
2018 }
2019
1397 bool Extension::LoadBackgroundScripts(string16* error) { 2020 bool Extension::LoadBackgroundScripts(string16* error) {
1398 Value* background_scripts_value = NULL; 2021 Value* background_scripts_value = NULL;
1399 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value)) 2022 if (!manifest_->Get(keys::kBackgroundScripts, &background_scripts_value))
1400 return true; 2023 return true;
1401 2024
1402 CHECK(background_scripts_value); 2025 CHECK(background_scripts_value);
1403 if (background_scripts_value->GetType() != Value::TYPE_LIST) { 2026 if (background_scripts_value->GetType() != Value::TYPE_LIST) {
1404 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); 2027 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts);
1405 return false; 2028 return false;
1406 } 2029 }
(...skipping 11 matching lines...) Expand all
1418 } 2041 }
1419 2042
1420 return true; 2043 return true;
1421 } 2044 }
1422 2045
1423 bool Extension::LoadBackgroundPage( 2046 bool Extension::LoadBackgroundPage(
1424 const ExtensionAPIPermissionSet& api_permissions, 2047 const ExtensionAPIPermissionSet& api_permissions,
1425 string16* error) { 2048 string16* error) {
1426 base::Value* background_page_value = NULL; 2049 base::Value* background_page_value = NULL;
1427 if (!manifest_->Get(keys::kBackgroundPage, &background_page_value)) 2050 if (!manifest_->Get(keys::kBackgroundPage, &background_page_value))
1428 manifest_->Get(keys::kBackgroundPageLegacy, &background_page_value); 2051 manifest_->Get(keys::kBackgroundPageLegacy, &background_page_value);
Yoyo Zhou 2012/03/01 01:17:25 leave the original indent
Devlin 2012/03/02 17:31:04 Whoops, didn't mean to do that. Done.
1429 2052
1430 if (!background_page_value) 2053 if (!background_page_value)
1431 return true; 2054 return true;
1432 2055
1433 std::string background_str; 2056 std::string background_str;
1434 if (!background_page_value->GetAsString(&background_str)) { 2057 if (!background_page_value->GetAsString(&background_str)) {
1435 *error = ASCIIToUTF16(errors::kInvalidBackground); 2058 *error = ASCIIToUTF16(errors::kInvalidBackground);
1436 return false; 2059 return false;
1437 } 2060 }
1438 2061
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1484 } 2107 }
1485 2108
1486 if (!has_background_page()) { 2109 if (!has_background_page()) {
1487 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); 2110 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage);
1488 return false; 2111 return false;
1489 } 2112 }
1490 2113
1491 return true; 2114 return true;
1492 } 2115 }
1493 2116
1494 // static 2117 bool Extension::LoadContentSecurityPolicy(string16* error) {
1495 bool Extension::IsTrustedId(const std::string& id) { 2118 if (manifest_->HasKey(keys::kContentSecurityPolicy)) {
1496 // See http://b/4946060 for more details. 2119 std::string content_security_policy;
1497 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); 2120 if (!manifest_->GetString(keys::kContentSecurityPolicy,
1498 } 2121 &content_security_policy)) {
1499 2122 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
1500 Extension::Extension(const FilePath& path, 2123 return false;
1501 scoped_ptr<extensions::Manifest> manifest) 2124 }
1502 : manifest_version_(0), 2125 if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
1503 incognito_split_mode_(false), 2126 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
1504 offline_enabled_(false), 2127 return false;
1505 converted_from_user_script_(false), 2128 }
1506 background_page_persists_(true), 2129 if (manifest_version_ >= 2 &&
1507 manifest_(manifest.release()), 2130 !ContentSecurityPolicyIsSecure(content_security_policy)) {
1508 is_storage_isolated_(false), 2131 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
1509 launch_container_(extension_misc::LAUNCH_TAB), 2132 return false;
1510 launch_width_(0), 2133 }
1511 launch_height_(0), 2134
1512 launch_min_width_(0), 2135 content_security_policy_ = content_security_policy;
1513 launch_min_height_(0), 2136 } else if (manifest_version_ >= 2) {
1514 wants_file_access_(false), 2137 // Manifest version 2 introduced a default Content-Security-Policy.
1515 creation_flags_(0) { 2138 // TODO(abarth): Should we continue to let extensions override the
1516 DCHECK(path.empty() || path.IsAbsolute()); 2139 // default Content-Security-Policy?
1517 path_ = MaybeNormalizePath(path); 2140 content_security_policy_ = kDefaultContentSecurityPolicy;
1518 } 2141 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_));
1519 2142 }
1520 Extension::~Extension() { 2143 return true;
1521 if (manifest_) 2144 }
1522 delete manifest_; 2145
1523 } 2146 // Load App settings. LoadExtent at least has to be done before
1524 2147 // ParsePermissions(), because the valid permissions depend on what type of
1525 ExtensionResource Extension::GetResource( 2148 // package this is.
Yoyo Zhou 2012/03/01 01:17:25 This comment belongs in InitValue (at this functio
Devlin 2012/03/02 17:31:04 Done.
1526 const std::string& relative_path) const { 2149 bool Extension::LoadAppFeatures(string16* error) {
1527 #if defined(OS_POSIX) 2150 if (!LoadExtent(keys::kWebURLs, &extent_,
1528 FilePath relative_file_path(relative_path); 2151 errors::kInvalidWebURLs, errors::kInvalidWebURL, error) ||
1529 #elif defined(OS_WIN) 2152 !LoadLaunchURL(error) ||
1530 FilePath relative_file_path(UTF8ToWide(relative_path)); 2153 !LoadLaunchContainer(error))
1531 #endif 2154 return false;
1532 return ExtensionResource(id(), path(), relative_file_path);
1533 }
1534
1535 ExtensionResource Extension::GetResource(
1536 const FilePath& relative_file_path) const {
1537 return ExtensionResource(id(), path(), relative_file_path);
1538 }
1539
1540 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
1541 // util class in base:
1542 // http://code.google.com/p/chromium/issues/detail?id=13572
1543 bool Extension::ParsePEMKeyBytes(const std::string& input,
1544 std::string* output) {
1545 DCHECK(output);
1546 if (!output)
1547 return false;
1548 if (input.length() == 0)
1549 return false;
1550
1551 std::string working = input;
1552 if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
1553 working = CollapseWhitespaceASCII(working, true);
1554 size_t header_pos = working.find(kKeyInfoEndMarker,
1555 sizeof(kKeyBeginHeaderMarker) - 1);
1556 if (header_pos == std::string::npos)
1557 return false;
1558 size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
1559 size_t end_pos = working.rfind(kKeyBeginFooterMarker);
1560 if (end_pos == std::string::npos)
1561 return false;
1562 if (start_pos >= end_pos)
1563 return false;
1564
1565 working = working.substr(start_pos, end_pos - start_pos);
1566 if (working.length() == 0)
1567 return false;
1568 }
1569
1570 return base::Base64Decode(working, output);
1571 }
1572
1573 bool Extension::ProducePEM(const std::string& input, std::string* output) {
1574 DCHECK(output);
1575 if (input.length() == 0)
1576 return false;
1577
1578 return base::Base64Encode(input, output);
1579 }
1580
1581 bool Extension::FormatPEMForFileOutput(const std::string& input,
1582 std::string* output,
1583 bool is_public) {
1584 DCHECK(output);
1585 if (input.length() == 0)
1586 return false;
1587 *output = "";
1588 output->append(kKeyBeginHeaderMarker);
1589 output->append(" ");
1590 output->append(is_public ? kPublic : kPrivate);
1591 output->append(" ");
1592 output->append(kKeyInfoEndMarker);
1593 output->append("\n");
1594 for (size_t i = 0; i < input.length(); ) {
1595 int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
1596 output->append(input.substr(i, slice));
1597 output->append("\n");
1598 i += slice;
1599 }
1600 output->append(kKeyBeginFooterMarker);
1601 output->append(" ");
1602 output->append(is_public ? kPublic : kPrivate);
1603 output->append(" ");
1604 output->append(kKeyInfoEndMarker);
1605 output->append("\n");
1606
1607 return true;
1608 }
1609
1610 // static
1611 void Extension::DecodeIcon(const Extension* extension,
1612 ExtensionIconSet::Icons preferred_icon_size,
1613 ExtensionIconSet::MatchType match_type,
1614 scoped_ptr<SkBitmap>* result) {
1615 std::string path = extension->icons().Get(preferred_icon_size, match_type);
1616 ExtensionIconSet::Icons size = extension->icons().GetIconSizeFromPath(path);
1617 ExtensionResource icon_resource = extension->GetResource(path);
1618 DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
1619 }
1620
1621 // static
1622 void Extension::DecodeIcon(const Extension* extension,
1623 ExtensionIconSet::Icons icon_size,
1624 scoped_ptr<SkBitmap>* result) {
1625 DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
1626 }
1627
1628 // static
1629 void Extension::DecodeIconFromPath(const FilePath& icon_path,
1630 ExtensionIconSet::Icons icon_size,
1631 scoped_ptr<SkBitmap>* result) {
1632 if (icon_path.empty())
1633 return;
1634
1635 std::string file_contents;
1636 if (!file_util::ReadFileToString(icon_path, &file_contents)) {
1637 DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
1638 return;
1639 }
1640
1641 // Decode the image using WebKit's image decoder.
1642 const unsigned char* data =
1643 reinterpret_cast<const unsigned char*>(file_contents.data());
1644 webkit_glue::ImageDecoder decoder;
1645 scoped_ptr<SkBitmap> decoded(new SkBitmap());
1646 *decoded = decoder.Decode(data, file_contents.length());
1647 if (decoded->empty()) {
1648 DLOG(ERROR) << "Could not decode icon file: "
1649 << icon_path.LossyDisplayName();
1650 return;
1651 }
1652
1653 if (decoded->width() != icon_size || decoded->height() != icon_size) {
1654 DLOG(ERROR) << "Icon file has unexpected size: "
1655 << base::IntToString(decoded->width()) << "x"
1656 << base::IntToString(decoded->height());
1657 return;
1658 }
1659
1660 result->swap(decoded);
1661 }
1662
1663 // static
1664 const SkBitmap& Extension::GetDefaultIcon(bool is_app) {
1665 if (is_app) {
1666 return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
1667 IDR_APP_DEFAULT_ICON);
1668 } else {
1669 return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
1670 IDR_EXTENSION_DEFAULT_ICON);
1671 }
1672 }
1673
1674 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
1675 return GURL(std::string(chrome::kExtensionScheme) +
1676 chrome::kStandardSchemeSeparator + extension_id + "/");
1677 }
1678
1679 bool Extension::LoadManifestVersion(string16* error) {
1680 // Get the original value out of the dictionary so that we can validate it
1681 // more strictly.
1682 if (manifest_->value()->HasKey(keys::kManifestVersion)) {
1683 int manifest_version = 1;
1684 if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
1685 manifest_version < 1) {
1686 *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
1687 return false;
1688 }
1689 }
1690
1691 manifest_version_ = manifest_->GetManifestVersion();
1692 if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
1693 manifest_version_ < kModernManifestVersion &&
1694 !CommandLine::ForCurrentProcess()->HasSwitch(
1695 switches::kAllowLegacyExtensionManifests)) {
1696 *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
1697 return false;
1698 }
1699
1700 return true;
1701 }
1702
1703 // static
1704 bool Extension::InitExtensionID(extensions::Manifest* manifest,
1705 const FilePath& path,
1706 const std::string& explicit_id,
1707 int creation_flags,
1708 string16* error) {
1709 if (!explicit_id.empty()) {
1710 manifest->set_extension_id(explicit_id);
1711 return true;
1712 }
1713
1714 if (manifest->HasKey(keys::kPublicKey)) {
1715 std::string public_key;
1716 std::string public_key_bytes;
1717 std::string extension_id;
1718 if (!manifest->GetString(keys::kPublicKey, &public_key) ||
1719 !ParsePEMKeyBytes(public_key, &public_key_bytes) ||
1720 !GenerateId(public_key_bytes, &extension_id)) {
1721 *error = ASCIIToUTF16(errors::kInvalidKey);
1722 return false;
1723 }
1724 manifest->set_extension_id(extension_id);
1725 return true;
1726 }
1727
1728 if (creation_flags & REQUIRE_KEY) {
1729 *error = ASCIIToUTF16(errors::kInvalidKey);
1730 return false;
1731 } else {
1732 // If there is a path, we generate the ID from it. This is useful for
1733 // development mode, because it keeps the ID stable across restarts and
1734 // reloading the extension.
1735 std::string extension_id = GenerateIdForPath(path);
1736 if (extension_id.empty()) {
1737 NOTREACHED() << "Could not create ID from path.";
1738 return false;
1739 }
1740 manifest->set_extension_id(extension_id);
1741 return true;
1742 }
1743 }
1744
1745 bool Extension::InitFromValue(int flags, string16* error) {
1746 DCHECK(error);
1747
1748 base::AutoLock auto_lock(runtime_data_lock_);
1749
1750 // Initialize permissions with an empty, default permission set.
1751 runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
1752 optional_permission_set_ = new ExtensionPermissionSet();
1753 required_permission_set_ = new ExtensionPermissionSet();
1754
1755 creation_flags_ = flags;
1756
1757 if (!LoadManifestVersion(error))
1758 return false;
1759
1760 // We don't ned to validate because InitExtensionID already did that.
1761 manifest_->GetString(keys::kPublicKey, &public_key_);
1762
1763 // Initialize the URL.
1764 extension_url_ = Extension::GetBaseURLFromExtensionId(id());
1765
1766 // Initialize version.
1767 std::string version_str;
1768 if (!manifest_->GetString(keys::kVersion, &version_str)) {
1769 *error = ASCIIToUTF16(errors::kInvalidVersion);
1770 return false;
1771 }
1772 version_.reset(Version::GetVersionFromString(version_str));
1773 if (!version_.get() ||
1774 version_->components().size() > 4) {
1775 *error = ASCIIToUTF16(errors::kInvalidVersion);
1776 return false;
1777 }
1778
1779 // Initialize name.
1780 string16 localized_name;
1781 if (!manifest_->GetString(keys::kName, &localized_name)) {
1782 *error = ASCIIToUTF16(errors::kInvalidName);
1783 return false;
1784 }
1785 base::i18n::AdjustStringForLocaleDirection(&localized_name);
1786 name_ = UTF16ToUTF8(localized_name);
1787
1788 // Load App settings. LoadExtent at least has to be done before
1789 // ParsePermissions(), because the valid permissions depend on what type of
1790 // package this is.
1791 if (is_app() &&
1792 (!LoadExtent(keys::kWebURLs, &extent_,errors::kInvalidWebURLs,
1793 errors::kInvalidWebURL, error) ||
1794 !LoadLaunchURL(error) ||
1795 !LoadLaunchContainer(error))) {
1796 return false;
1797 }
1798 2155
1799 if (is_platform_app()) { 2156 if (is_platform_app()) {
1800 if (launch_container() != extension_misc::LAUNCH_SHELL) { 2157 if (launch_container() != extension_misc::LAUNCH_SHELL) {
1801 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform); 2158 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForPlatform);
1802 return false; 2159 return false;
1803 } 2160 }
1804 } else if (launch_container() == extension_misc::LAUNCH_SHELL) { 2161 } else if (launch_container() == extension_misc::LAUNCH_SHELL) {
1805 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform); 2162 *error = ASCIIToUTF16(errors::kInvalidLaunchContainerForNonPlatform);
1806 return false; 2163 return false;
1807 } 2164 }
1808 2165
1809 // Initialize the permissions (optional). 2166 return true;
2167 }
2168
2169 bool Extension::LoadExtent(const char* key,
2170 URLPatternSet* extent,
2171 const char* list_error,
2172 const char* value_error,
2173 string16* error) {
2174 Value* temp = NULL;
2175 if (!manifest_->Get(key, &temp))
2176 return true;
2177
2178 if (temp->GetType() != Value::TYPE_LIST) {
2179 *error = ASCIIToUTF16(list_error);
2180 return false;
2181 }
2182
2183 ListValue* pattern_list = static_cast<ListValue*>(temp);
2184 for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
2185 std::string pattern_string;
2186 if (!pattern_list->GetString(i, &pattern_string)) {
2187 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(value_error,
2188 base::UintToString(i),
2189 errors::kExpectString);
2190 return false;
2191 }
2192
2193 URLPattern pattern(kValidWebExtentSchemes);
2194 URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
2195 if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
2196 pattern_string += "/";
2197 parse_result = pattern.Parse(pattern_string);
2198 }
2199
2200 if (parse_result != URLPattern::PARSE_SUCCESS) {
2201 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2202 value_error,
2203 base::UintToString(i),
2204 URLPattern::GetParseResultString(parse_result));
2205 return false;
2206 }
2207
2208 // Do not allow authors to claim "<all_urls>".
2209 if (pattern.match_all_urls()) {
2210 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2211 value_error,
2212 base::UintToString(i),
2213 errors::kCannotClaimAllURLsInExtent);
2214 return false;
2215 }
2216
2217 // Do not allow authors to claim "*" for host.
2218 if (pattern.host().empty()) {
2219 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2220 value_error,
2221 base::UintToString(i),
2222 errors::kCannotClaimAllHostsInExtent);
2223 return false;
2224 }
2225
2226 // We do not allow authors to put wildcards in their paths. Instead, we
2227 // imply one at the end.
2228 if (pattern.path().find('*') != std::string::npos) {
2229 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2230 value_error,
2231 base::UintToString(i),
2232 errors::kNoWildCardsInPaths);
2233 return false;
2234 }
2235 pattern.SetPath(pattern.path() + '*');
2236
2237 extent->AddPattern(pattern);
2238 }
2239
2240 return true;
2241 }
2242
2243 bool Extension::LoadLaunchURL(string16* error) {
2244 Value* temp = NULL;
2245
2246 // launch URL can be either local (to chrome-extension:// root) or an absolute
2247 // web URL.
2248 if (manifest_->Get(keys::kLaunchLocalPath, &temp)) {
2249 if (manifest_->Get(keys::kLaunchWebURL, NULL)) {
2250 *error = ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive);
2251 return false;
2252 }
2253
2254 if (manifest_->Get(keys::kWebURLs, NULL)) {
2255 *error = ASCIIToUTF16(errors::kLaunchPathAndExtentAreExclusive);
2256 return false;
2257 }
2258
2259 std::string launch_path;
2260 if (!temp->GetAsString(&launch_path)) {
2261 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2262 errors::kInvalidLaunchValue,
2263 keys::kLaunchLocalPath);
2264 return false;
2265 }
2266
2267 // Ensure the launch path is a valid relative URL.
2268 GURL resolved = url().Resolve(launch_path);
2269 if (!resolved.is_valid() || resolved.GetOrigin() != url()) {
2270 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2271 errors::kInvalidLaunchValue,
2272 keys::kLaunchLocalPath);
2273 return false;
2274 }
2275
2276 launch_local_path_ = launch_path;
2277 } else if (manifest_->Get(keys::kLaunchWebURL, &temp)) {
2278 std::string launch_url;
2279 if (!temp->GetAsString(&launch_url)) {
2280 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2281 errors::kInvalidLaunchValue,
2282 keys::kLaunchWebURL);
2283 return false;
2284 }
2285
2286 // Ensure the launch URL is a valid absolute URL and web extent scheme.
2287 GURL url(launch_url);
2288 URLPattern pattern(kValidWebExtentSchemes);
2289 if (!url.is_valid() || !pattern.SetScheme(url.scheme())) {
2290 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2291 errors::kInvalidLaunchValue,
2292 keys::kLaunchWebURL);
2293 return false;
2294 }
2295
2296 launch_web_url_ = launch_url;
2297 } else if (is_app()) {
2298 *error = ASCIIToUTF16(errors::kLaunchURLRequired);
2299 return false;
2300 }
2301
2302 // If there is no extent, we default the extent based on the launch URL.
2303 if (web_extent().is_empty() && !launch_web_url().empty()) {
2304 GURL launch_url(launch_web_url());
2305 URLPattern pattern(kValidWebExtentSchemes);
2306 if (!pattern.SetScheme("*")) {
2307 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2308 errors::kInvalidLaunchValue,
2309 keys::kLaunchWebURL);
2310 return false;
2311 }
2312 pattern.SetHost(launch_url.host());
2313 pattern.SetPath("/*");
2314 extent_.AddPattern(pattern);
2315 }
2316
2317 // In order for the --apps-gallery-url switch to work with the gallery
2318 // process isolation, we must insert any provided value into the component
2319 // app's launch url and web extent.
2320 if (id() == extension_misc::kWebStoreAppId) {
2321 std::string gallery_url_str = CommandLine::ForCurrentProcess()->
2322 GetSwitchValueASCII(switches::kAppsGalleryURL);
2323
2324 // Empty string means option was not used.
2325 if (!gallery_url_str.empty()) {
2326 GURL gallery_url(gallery_url_str);
2327 OverrideLaunchUrl(gallery_url);
2328 }
2329 } else if (id() == extension_misc::kCloudPrintAppId) {
2330 // In order for the --cloud-print-service switch to work, we must update
2331 // the launch URL and web extent.
2332 // TODO(sanjeevr): Ideally we want to use CloudPrintURL here but that is
2333 // currently under chrome/browser.
2334 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
2335 GURL cloud_print_service_url = GURL(command_line.GetSwitchValueASCII(
2336 switches::kCloudPrintServiceURL));
2337 if (!cloud_print_service_url.is_empty()) {
2338 std::string path(
2339 cloud_print_service_url.path() + "/enable_chrome_connector");
2340 GURL::Replacements replacements;
2341 replacements.SetPathStr(path);
2342 GURL cloud_print_enable_connector_url =
2343 cloud_print_service_url.ReplaceComponents(replacements);
2344 OverrideLaunchUrl(cloud_print_enable_connector_url);
2345 }
2346 }
2347 return true;
2348 }
2349
2350 bool ReadLaunchDimension(const extensions::Manifest* manifest,
2351 const char* key,
2352 int* target,
2353 bool is_valid_container,
2354 string16* error) {
2355 Value* temp = NULL;
2356 if (manifest->Get(key, &temp)) {
2357 if (!is_valid_container) {
2358 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2359 errors::kInvalidLaunchValueContainer,
2360 key);
2361 return false;
2362 }
2363 if (!temp->GetAsInteger(target) || *target < 0) {
2364 *target = 0;
2365 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2366 errors::kInvalidLaunchValue,
2367 key);
2368 return false;
2369 }
2370 }
2371 return true;
2372 }
2373
2374 bool Extension::LoadLaunchContainer(string16* error) {
2375 Value* temp = NULL;
2376 if (!manifest_->Get(keys::kLaunchContainer, &temp))
2377 return true;
2378
2379 std::string launch_container_string;
2380 if (!temp->GetAsString(&launch_container_string)) {
2381 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
2382 return false;
2383 }
2384
2385 if (launch_container_string == values::kLaunchContainerShell) {
2386 launch_container_ = extension_misc::LAUNCH_SHELL;
2387 } else if (launch_container_string == values::kLaunchContainerPanel) {
2388 launch_container_ = extension_misc::LAUNCH_PANEL;
2389 } else if (launch_container_string == values::kLaunchContainerTab) {
2390 launch_container_ = extension_misc::LAUNCH_TAB;
2391 } else {
2392 *error = ASCIIToUTF16(errors::kInvalidLaunchContainer);
2393 return false;
2394 }
2395
2396 bool can_specify_initial_size =
2397 launch_container() == extension_misc::LAUNCH_PANEL ||
2398 launch_container() == extension_misc::LAUNCH_WINDOW ||
2399 launch_container() == extension_misc::LAUNCH_SHELL;
2400
2401 // Validate the container width if present.
2402 if (!ReadLaunchDimension(manifest_,
2403 keys::kLaunchWidth,
2404 &launch_width_,
2405 can_specify_initial_size,
2406 error))
2407 return false;
2408
2409 // Validate container height if present.
2410 if (!ReadLaunchDimension(manifest_,
2411 keys::kLaunchHeight,
2412 &launch_height_,
2413 can_specify_initial_size,
2414 error))
2415 return false;
2416
2417 bool can_specify_size_range =
2418 launch_container() == extension_misc::LAUNCH_SHELL;
2419
2420 // Validate min size if present.
2421 if (!ReadLaunchDimension(manifest_,
2422 keys::kLaunchMinWidth,
2423 &launch_min_width_,
2424 can_specify_size_range,
2425 error))
2426 return false;
2427 if (!ReadLaunchDimension(manifest_,
2428 keys::kLaunchMinHeight,
2429 &launch_min_height_,
2430 can_specify_size_range,
2431 error))
2432 return false;
2433
2434 if (launch_container() == extension_misc::LAUNCH_SHELL) {
2435 if (!manifest_->Get(keys::kLaunchWidth, &temp)) {
2436 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2437 errors::kInvalidLaunchValue,
2438 keys::kLaunchWidth);
2439 return false;
2440 }
2441 if (!manifest_->Get(keys::kLaunchHeight, &temp)) {
2442 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2443 errors::kInvalidLaunchValue,
2444 keys::kLaunchHeight);
2445 return false;
2446 }
2447 }
2448
2449 return true;
2450 }
2451
2452
2453 bool Extension::LoadAppIsolation(string16* error) {
2454 Value* temp = NULL;
2455 if (!manifest_->Get(keys::kIsolation, &temp))
2456 return true;
2457
2458 if (temp->GetType() != Value::TYPE_LIST) {
2459 *error = ASCIIToUTF16(errors::kInvalidIsolation);
2460 return false;
2461 }
2462
2463 ListValue* isolation_list = static_cast<ListValue*>(temp);
2464 for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
2465 std::string isolation_string;
2466 if (!isolation_list->GetString(i, &isolation_string)) {
2467 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2468 errors::kInvalidIsolationValue,
2469 base::UintToString(i));
2470 return false;
2471 }
2472
2473 // Check for isolated storage.
2474 if (isolation_string == values::kIsolatedStorage) {
2475 is_storage_isolated_ = true;
2476 } else {
2477 DLOG(WARNING) << "Did not recognize isolation type: "
2478 << isolation_string;
2479 }
2480 }
2481 return true;
2482 }
2483
2484 bool Extension::LoadThemeFeatures(string16* error) {
2485 DictionaryValue* theme_value = NULL;
2486 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) {
2487 *error = ASCIIToUTF16(errors::kInvalidTheme);
2488 return false;
2489 }
2490 if (!LoadThemeImages(theme_value, error))
2491 return false;
2492 if (!LoadThemeColors(theme_value, error))
2493 return false;
2494 if (!LoadThemeTints(theme_value, error))
2495 return false;
2496 if (!LoadThemeDisplayProperties(theme_value, error))
2497 return false;
2498
2499 return true;
2500 }
2501
2502 bool Extension::LoadThemeImages(const DictionaryValue* theme_value,
2503 string16* error) {
2504 DictionaryValue* images_value = NULL;
2505 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
2506 // Validate that the images are all strings
2507 for (DictionaryValue::key_iterator iter = images_value->begin_keys();
2508 iter != images_value->end_keys(); ++iter) {
2509 std::string val;
2510 if (!images_value->GetString(*iter, &val)) {
2511 *error = ASCIIToUTF16(errors::kInvalidThemeImages);
2512 return false;
2513 }
2514 }
2515 theme_images_.reset(images_value->DeepCopy());
2516 }
2517 return true;
2518 }
2519
2520 bool Extension::LoadThemeColors(const DictionaryValue* theme_value,
2521 string16* error) {
2522 DictionaryValue* colors_value = NULL;
2523 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
2524 // Validate that the colors are RGB or RGBA lists
2525 for (DictionaryValue::key_iterator iter = colors_value->begin_keys();
2526 iter != colors_value->end_keys(); ++iter) {
2527 ListValue* color_list = NULL;
2528 double alpha = 0.0;
2529 int color = 0;
2530 // The color must be a list
2531 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) ||
2532 // And either 3 items (RGB) or 4 (RGBA)
2533 ((color_list->GetSize() != 3) &&
2534 ((color_list->GetSize() != 4) ||
2535 // For RGBA, the fourth item must be a real or int alpha value.
2536 // Note that GetDouble() can get an integer value.
2537 !color_list->GetDouble(3, &alpha))) ||
2538 // For both RGB and RGBA, the first three items must be ints (R,G,B)
2539 !color_list->GetInteger(0, &color) ||
2540 !color_list->GetInteger(1, &color) ||
2541 !color_list->GetInteger(2, &color)) {
2542 *error = ASCIIToUTF16(errors::kInvalidThemeColors);
2543 return false;
2544 }
2545 }
2546 theme_colors_.reset(colors_value->DeepCopy());
2547 }
2548 return true;
2549 }
2550
2551 bool Extension::LoadThemeTints(const DictionaryValue* theme_value,
2552 string16* error) {
2553 DictionaryValue* tints_value = NULL;
2554 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) {
2555 // Validate that the tints are all reals.
2556 for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
2557 iter != tints_value->end_keys(); ++iter) {
2558 ListValue* tint_list = NULL;
2559 double v = 0.0;
2560 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) ||
2561 tint_list->GetSize() != 3 ||
2562 !tint_list->GetDouble(0, &v) ||
2563 !tint_list->GetDouble(1, &v) ||
2564 !tint_list->GetDouble(2, &v)) {
2565 *error = ASCIIToUTF16(errors::kInvalidThemeTints);
2566 return false;
2567 }
2568 }
2569 theme_tints_.reset(tints_value->DeepCopy());
2570 }
2571 return true;
2572 }
2573
2574 bool Extension::LoadThemeDisplayProperties(const DictionaryValue* theme_value,
2575 string16* error) {
2576 DictionaryValue* display_properties_value = NULL;
2577 if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
2578 &display_properties_value)) {
2579 theme_display_properties_.reset(
2580 display_properties_value->DeepCopy());
2581 }
2582 return true;
2583 }
2584
2585 // static
2586 bool Extension::IsTrustedId(const std::string& id) {
2587 // See http://b/4946060 for more details.
2588 return id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
2589 }
2590
2591 Extension::Extension(const FilePath& path,
2592 scoped_ptr<extensions::Manifest> manifest)
2593 : manifest_version_(0),
2594 incognito_split_mode_(false),
2595 offline_enabled_(false),
2596 converted_from_user_script_(false),
2597 background_page_persists_(true),
2598 manifest_(manifest.release()),
2599 is_storage_isolated_(false),
2600 launch_container_(extension_misc::LAUNCH_TAB),
2601 launch_width_(0),
2602 launch_height_(0),
2603 launch_min_width_(0),
2604 launch_min_height_(0),
2605 wants_file_access_(false),
2606 creation_flags_(0) {
2607 DCHECK(path.empty() || path.IsAbsolute());
2608 path_ = MaybeNormalizePath(path);
2609 }
2610
2611 Extension::~Extension() {
2612 if (manifest_)
2613 delete manifest_;
2614 }
2615
2616 ExtensionResource Extension::GetResource(
2617 const std::string& relative_path) const {
2618 #if defined(OS_POSIX)
2619 FilePath relative_file_path(relative_path);
2620 #elif defined(OS_WIN)
2621 FilePath relative_file_path(UTF8ToWide(relative_path));
2622 #endif
2623 return ExtensionResource(id(), path(), relative_file_path);
2624 }
2625
2626 ExtensionResource Extension::GetResource(
2627 const FilePath& relative_file_path) const {
2628 return ExtensionResource(id(), path(), relative_file_path);
2629 }
2630
2631 // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
2632 // util class in base:
2633 // http://code.google.com/p/chromium/issues/detail?id=13572
2634 bool Extension::ParsePEMKeyBytes(const std::string& input,
2635 std::string* output) {
2636 DCHECK(output);
2637 if (!output)
2638 return false;
2639 if (input.length() == 0)
2640 return false;
2641
2642 std::string working = input;
2643 if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
2644 working = CollapseWhitespaceASCII(working, true);
2645 size_t header_pos = working.find(kKeyInfoEndMarker,
2646 sizeof(kKeyBeginHeaderMarker) - 1);
2647 if (header_pos == std::string::npos)
2648 return false;
2649 size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
2650 size_t end_pos = working.rfind(kKeyBeginFooterMarker);
2651 if (end_pos == std::string::npos)
2652 return false;
2653 if (start_pos >= end_pos)
2654 return false;
2655
2656 working = working.substr(start_pos, end_pos - start_pos);
2657 if (working.length() == 0)
2658 return false;
2659 }
2660
2661 return base::Base64Decode(working, output);
2662 }
2663
2664 bool Extension::ProducePEM(const std::string& input, std::string* output) {
2665 DCHECK(output);
2666 if (input.length() == 0)
2667 return false;
2668
2669 return base::Base64Encode(input, output);
2670 }
2671
2672 bool Extension::FormatPEMForFileOutput(const std::string& input,
2673 std::string* output,
2674 bool is_public) {
2675 DCHECK(output);
2676 if (input.length() == 0)
2677 return false;
2678 *output = "";
2679 output->append(kKeyBeginHeaderMarker);
2680 output->append(" ");
2681 output->append(is_public ? kPublic : kPrivate);
2682 output->append(" ");
2683 output->append(kKeyInfoEndMarker);
2684 output->append("\n");
2685 for (size_t i = 0; i < input.length(); ) {
2686 int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
2687 output->append(input.substr(i, slice));
2688 output->append("\n");
2689 i += slice;
2690 }
2691 output->append(kKeyBeginFooterMarker);
2692 output->append(" ");
2693 output->append(is_public ? kPublic : kPrivate);
2694 output->append(" ");
2695 output->append(kKeyInfoEndMarker);
2696 output->append("\n");
2697
2698 return true;
2699 }
2700
2701 // static
2702 void Extension::DecodeIcon(const Extension* extension,
2703 ExtensionIconSet::Icons preferred_icon_size,
2704 ExtensionIconSet::MatchType match_type,
2705 scoped_ptr<SkBitmap>* result) {
2706 std::string path = extension->icons().Get(preferred_icon_size, match_type);
2707 ExtensionIconSet::Icons size = extension->icons().GetIconSizeFromPath(path);
2708 ExtensionResource icon_resource = extension->GetResource(path);
2709 DecodeIconFromPath(icon_resource.GetFilePath(), size, result);
2710 }
2711
2712 // static
2713 void Extension::DecodeIcon(const Extension* extension,
2714 ExtensionIconSet::Icons icon_size,
2715 scoped_ptr<SkBitmap>* result) {
2716 DecodeIcon(extension, icon_size, ExtensionIconSet::MATCH_EXACTLY, result);
2717 }
2718
2719 // static
2720 void Extension::DecodeIconFromPath(const FilePath& icon_path,
2721 ExtensionIconSet::Icons icon_size,
2722 scoped_ptr<SkBitmap>* result) {
2723 if (icon_path.empty())
2724 return;
2725
2726 std::string file_contents;
2727 if (!file_util::ReadFileToString(icon_path, &file_contents)) {
2728 DLOG(ERROR) << "Could not read icon file: " << icon_path.LossyDisplayName();
2729 return;
2730 }
2731
2732 // Decode the image using WebKit's image decoder.
2733 const unsigned char* data =
2734 reinterpret_cast<const unsigned char*>(file_contents.data());
2735 webkit_glue::ImageDecoder decoder;
2736 scoped_ptr<SkBitmap> decoded(new SkBitmap());
2737 *decoded = decoder.Decode(data, file_contents.length());
2738 if (decoded->empty()) {
2739 DLOG(ERROR) << "Could not decode icon file: "
2740 << icon_path.LossyDisplayName();
2741 return;
2742 }
2743
2744 if (decoded->width() != icon_size || decoded->height() != icon_size) {
2745 DLOG(ERROR) << "Icon file has unexpected size: "
2746 << base::IntToString(decoded->width()) << "x"
2747 << base::IntToString(decoded->height());
2748 return;
2749 }
2750
2751 result->swap(decoded);
2752 }
2753
2754 // static
2755 const SkBitmap& Extension::GetDefaultIcon(bool is_app) {
2756 if (is_app) {
2757 return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
2758 IDR_APP_DEFAULT_ICON);
2759 } else {
2760 return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
2761 IDR_EXTENSION_DEFAULT_ICON);
2762 }
2763 }
2764
2765 GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
Yoyo Zhou 2012/03/01 01:17:25 Put a // static before this.
2766 return GURL(std::string(chrome::kExtensionScheme) +
2767 chrome::kStandardSchemeSeparator + extension_id + "/");
2768 }
2769
2770 bool Extension::InitFromValue(int flags, string16* error) {
2771 DCHECK(error);
2772
2773 base::AutoLock auto_lock(runtime_data_lock_);
2774
2775 // Initialize permissions with an empty, default permission set.
2776 runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
2777 optional_permission_set_ = new ExtensionPermissionSet();
2778 required_permission_set_ = new ExtensionPermissionSet();
2779
2780 creation_flags_ = flags;
2781
2782 if (!LoadManifestVersion(error))
2783 return false;
2784
2785 // We don't ned to validate because InitExtensionID already did that.
2786 manifest_->GetString(keys::kPublicKey, &public_key_);
2787
2788 // Initialize permissions with an empty, default permission set.
2789 runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
2790 optional_permission_set_ = new ExtensionPermissionSet();
2791 required_permission_set_ = new ExtensionPermissionSet();
2792
2793 if (!LoadSharedFeatures(flags, error))
Yoyo Zhou 2012/03/01 01:17:25 In this and in LoadExtensionFeatures and whatever
2794 return false;
2795
2796 if (is_app() && !LoadAppFeatures(error))
2797 return false;
2798
1810 ExtensionAPIPermissionSet api_permissions; 2799 ExtensionAPIPermissionSet api_permissions;
1811 URLPatternSet host_permissions; 2800 URLPatternSet host_permissions;
1812 if (!ParsePermissions(keys::kPermissions, 2801 if (!ParsePermissions(keys::kPermissions,
1813 flags, 2802 flags,
1814 error, 2803 error,
1815 &api_permissions, 2804 &api_permissions,
1816 &host_permissions)) { 2805 &host_permissions)) {
1817 return false; 2806 return false;
1818 } 2807 }
1819 2808
1820 // Initialize the optional permissions (optional).
1821 ExtensionAPIPermissionSet optional_api_permissions; 2809 ExtensionAPIPermissionSet optional_api_permissions;
1822 URLPatternSet optional_host_permissions; 2810 URLPatternSet optional_host_permissions;
1823 if (!ParsePermissions(keys::kOptionalPermissions, 2811 if (!ParsePermissions(keys::kOptionalPermissions,
1824 flags, 2812 flags,
1825 error, 2813 error,
1826 &optional_api_permissions, 2814 &optional_api_permissions,
1827 &optional_host_permissions)) { 2815 &optional_host_permissions)) {
1828 return false; 2816 return false;
1829 } 2817 }
1830 2818
1831 // Initialize description (if present).
1832 if (manifest_->HasKey(keys::kDescription)) {
1833 if (!manifest_->GetString(keys::kDescription, &description_)) {
1834 *error = ASCIIToUTF16(errors::kInvalidDescription);
1835 return false;
1836 }
1837 }
1838
1839 // Initialize homepage url (if present).
1840 if (manifest_->HasKey(keys::kHomepageURL)) {
1841 std::string tmp;
1842 if (!manifest_->GetString(keys::kHomepageURL, &tmp)) {
1843 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1844 errors::kInvalidHomepageURL, "");
1845 return false;
1846 }
1847 homepage_url_ = GURL(tmp);
1848 if (!homepage_url_.is_valid() ||
1849 (!homepage_url_.SchemeIs("http") &&
1850 !homepage_url_.SchemeIs("https"))) {
1851 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1852 errors::kInvalidHomepageURL, tmp);
1853 return false;
1854 }
1855 }
1856
1857 // Initialize update url (if present).
1858 if (manifest_->HasKey(keys::kUpdateURL)) {
1859 std::string tmp;
1860 if (!manifest_->GetString(keys::kUpdateURL, &tmp)) {
1861 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1862 errors::kInvalidUpdateURL, "");
1863 return false;
1864 }
1865 update_url_ = GURL(tmp);
1866 if (!update_url_.is_valid() ||
1867 update_url_.has_ref()) {
1868 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1869 errors::kInvalidUpdateURL, tmp);
1870 return false;
1871 }
1872 }
1873
1874 // Validate minimum Chrome version (if present). We don't need to store this,
1875 // since the extension is not valid if it is incorrect.
1876 if (manifest_->HasKey(keys::kMinimumChromeVersion)) {
1877 std::string minimum_version_string;
1878 if (!manifest_->GetString(keys::kMinimumChromeVersion,
1879 &minimum_version_string)) {
1880 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
1881 return false;
1882 }
1883
1884 scoped_ptr<Version> minimum_version(
1885 Version::GetVersionFromString(minimum_version_string));
1886 if (!minimum_version.get()) {
1887 *error = ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
1888 return false;
1889 }
1890
1891 chrome::VersionInfo current_version_info;
1892 if (!current_version_info.is_valid()) {
1893 NOTREACHED();
1894 return false;
1895 }
1896
1897 scoped_ptr<Version> current_version(
1898 Version::GetVersionFromString(current_version_info.Version()));
1899 if (!current_version.get()) {
1900 DCHECK(false);
1901 return false;
1902 }
1903
1904 if (current_version->CompareTo(*minimum_version) < 0) {
1905 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1906 errors::kChromeVersionTooLow,
1907 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
1908 minimum_version_string);
1909 return false;
1910 }
1911 }
1912
1913 // Initialize converted_from_user_script (if present)
1914 if (manifest_->HasKey(keys::kConvertedFromUserScript))
1915 manifest_->GetBoolean(keys::kConvertedFromUserScript,
1916 &converted_from_user_script_);
1917
1918 // Initialize commands (if present).
1919 if (manifest_->HasKey(keys::kCommands)) {
1920 DictionaryValue* commands = NULL;
1921 if (!manifest_->GetDictionary(keys::kCommands, &commands)) {
1922 *error = ASCIIToUTF16(errors::kInvalidCommandsKey);
1923 return false;
1924 }
1925
1926 int command_index = 0;
1927 for (DictionaryValue::key_iterator iter = commands->begin_keys();
1928 iter != commands->end_keys(); ++iter) {
1929 ++command_index;
1930
1931 DictionaryValue* command = NULL;
1932 if (!commands->GetDictionary(*iter, &command)) {
1933 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1934 errors::kInvalidKeyBindingDictionary,
1935 base::IntToString(command_index));
1936 return false;
1937 }
1938
1939 ExtensionKeybinding binding;
1940 if (!binding.Parse(command, *iter, command_index, error))
1941 return false; // |error| already set.
1942
1943 commands_.push_back(binding);
1944 }
1945 }
1946
1947 // Initialize icons (if present).
1948 if (manifest_->HasKey(keys::kIcons)) {
1949 DictionaryValue* icons_value = NULL;
1950 if (!manifest_->GetDictionary(keys::kIcons, &icons_value)) {
1951 *error = ASCIIToUTF16(errors::kInvalidIcons);
1952 return false;
1953 }
1954
1955 for (size_t i = 0; i < ExtensionIconSet::kNumIconSizes; ++i) {
1956 std::string key = base::IntToString(ExtensionIconSet::kIconSizes[i]);
1957 if (icons_value->HasKey(key)) {
1958 std::string icon_path;
1959 if (!icons_value->GetString(key, &icon_path)) {
1960 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1961 errors::kInvalidIconPath, key);
1962 return false;
1963 }
1964
1965 if (!icon_path.empty() && icon_path[0] == '/')
1966 icon_path = icon_path.substr(1);
1967
1968 if (icon_path.empty()) {
1969 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1970 errors::kInvalidIconPath, key);
1971 return false;
1972 }
1973
1974 icons_.Add(ExtensionIconSet::kIconSizes[i], icon_path);
1975 }
1976 }
1977 }
1978
1979 // Initialize themes (if present).
1980 if (manifest_->HasKey(keys::kTheme)) {
1981 DictionaryValue* theme_value = NULL;
1982 if (!manifest_->GetDictionary(keys::kTheme, &theme_value)) {
1983 *error = ASCIIToUTF16(errors::kInvalidTheme);
1984 return false;
1985 }
1986
1987 DictionaryValue* images_value = NULL;
1988 if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
1989 // Validate that the images are all strings
1990 for (DictionaryValue::key_iterator iter = images_value->begin_keys();
1991 iter != images_value->end_keys(); ++iter) {
1992 std::string val;
1993 if (!images_value->GetString(*iter, &val)) {
1994 *error = ASCIIToUTF16(errors::kInvalidThemeImages);
1995 return false;
1996 }
1997 }
1998 theme_images_.reset(images_value->DeepCopy());
1999 }
2000
2001 DictionaryValue* colors_value = NULL;
2002 if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
2003 // Validate that the colors are RGB or RGBA lists
2004 for (DictionaryValue::key_iterator iter = colors_value->begin_keys();
2005 iter != colors_value->end_keys(); ++iter) {
2006 ListValue* color_list = NULL;
2007 double alpha = 0.0;
2008 int color = 0;
2009 // The color must be a list
2010 if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) ||
2011 // And either 3 items (RGB) or 4 (RGBA)
2012 ((color_list->GetSize() != 3) &&
2013 ((color_list->GetSize() != 4) ||
2014 // For RGBA, the fourth item must be a real or int alpha value.
2015 // Note that GetDouble() can get an integer value.
2016 !color_list->GetDouble(3, &alpha))) ||
2017 // For both RGB and RGBA, the first three items must be ints (R,G,B)
2018 !color_list->GetInteger(0, &color) ||
2019 !color_list->GetInteger(1, &color) ||
2020 !color_list->GetInteger(2, &color)) {
2021 *error = ASCIIToUTF16(errors::kInvalidThemeColors);
2022 return false;
2023 }
2024 }
2025 theme_colors_.reset(colors_value->DeepCopy());
2026 }
2027
2028 DictionaryValue* tints_value = NULL;
2029 if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) {
2030 // Validate that the tints are all reals.
2031 for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
2032 iter != tints_value->end_keys(); ++iter) {
2033 ListValue* tint_list = NULL;
2034 double v = 0.0;
2035 if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) ||
2036 tint_list->GetSize() != 3 ||
2037 !tint_list->GetDouble(0, &v) ||
2038 !tint_list->GetDouble(1, &v) ||
2039 !tint_list->GetDouble(2, &v)) {
2040 *error = ASCIIToUTF16(errors::kInvalidThemeTints);
2041 return false;
2042 }
2043 }
2044 theme_tints_.reset(tints_value->DeepCopy());
2045 }
2046
2047 DictionaryValue* display_properties_value = NULL;
2048 if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
2049 &display_properties_value)) {
2050 theme_display_properties_.reset(
2051 display_properties_value->DeepCopy());
2052 }
2053
2054 return true;
2055 }
2056
2057 // Initialize plugins (optional).
2058 if (manifest_->HasKey(keys::kPlugins)) {
2059 ListValue* list_value = NULL;
2060 if (!manifest_->GetList(keys::kPlugins, &list_value)) {
2061 *error = ASCIIToUTF16(errors::kInvalidPlugins);
2062 return false;
2063 }
2064
2065 for (size_t i = 0; i < list_value->GetSize(); ++i) {
2066 DictionaryValue* plugin_value = NULL;
2067 std::string path_str;
2068 bool is_public = false;
2069
2070 if (!list_value->GetDictionary(i, &plugin_value)) {
2071 *error = ASCIIToUTF16(errors::kInvalidPlugins);
2072 return false;
2073 }
2074
2075 // Get plugins[i].path.
2076 if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
2077 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2078 errors::kInvalidPluginsPath, base::IntToString(i));
2079 return false;
2080 }
2081
2082 // Get plugins[i].content (optional).
2083 if (plugin_value->HasKey(keys::kPluginsPublic)) {
2084 if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
2085 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2086 errors::kInvalidPluginsPublic, base::IntToString(i));
2087 return false;
2088 }
2089 }
2090
2091 // We don't allow extension plugins to run on Chrome OS. We still
2092 // parse the manifest entry so that error messages are consistently
2093 // displayed across platforms.
2094 #if !defined(OS_CHROMEOS)
2095 plugins_.push_back(PluginInfo());
2096 plugins_.back().path = path().Append(FilePath::FromUTF8Unsafe(path_str));
2097 plugins_.back().is_public = is_public;
2098 #endif
2099 }
2100 }
2101
2102 if (manifest_->HasKey(keys::kNaClModules)) {
2103 ListValue* list_value = NULL;
2104 if (!manifest_->GetList(keys::kNaClModules, &list_value)) {
2105 *error = ASCIIToUTF16(errors::kInvalidNaClModules);
2106 return false;
2107 }
2108
2109 for (size_t i = 0; i < list_value->GetSize(); ++i) {
2110 DictionaryValue* module_value = NULL;
2111 std::string path_str;
2112 std::string mime_type;
2113
2114 if (!list_value->GetDictionary(i, &module_value)) {
2115 *error = ASCIIToUTF16(errors::kInvalidNaClModules);
2116 return false;
2117 }
2118
2119 // Get nacl_modules[i].path.
2120 if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
2121 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2122 errors::kInvalidNaClModulesPath, base::IntToString(i));
2123 return false;
2124 }
2125
2126 // Get nacl_modules[i].mime_type.
2127 if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
2128 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2129 errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
2130 return false;
2131 }
2132
2133 nacl_modules_.push_back(NaClModuleInfo());
2134 nacl_modules_.back().url = GetResourceURL(path_str);
2135 nacl_modules_.back().mime_type = mime_type;
2136 }
2137 }
2138
2139 // Initialize content scripts (optional).
2140 if (manifest_->HasKey(keys::kContentScripts)) {
2141 ListValue* list_value;
2142 if (!manifest_->GetList(keys::kContentScripts, &list_value)) {
2143 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList);
2144 return false;
2145 }
2146
2147 for (size_t i = 0; i < list_value->GetSize(); ++i) {
2148 DictionaryValue* content_script = NULL;
2149 if (!list_value->GetDictionary(i, &content_script)) {
2150 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2151 errors::kInvalidContentScript, base::IntToString(i));
2152 return false;
2153 }
2154
2155 UserScript script;
2156 if (!LoadUserScriptHelper(content_script, i, flags, error, &script))
2157 return false; // Failed to parse script context definition.
2158 script.set_extension_id(id());
2159 if (converted_from_user_script_) {
2160 script.set_emulate_greasemonkey(true);
2161 script.set_match_all_frames(true); // Greasemonkey matches all frames.
2162 }
2163 content_scripts_.push_back(script);
2164 }
2165 }
2166
2167 // Initialize web accessible resources (optional).
2168 if (manifest_->HasKey(keys::kWebAccessibleResources)) {
2169 ListValue* list_value;
2170 if (!manifest_->GetList(keys::kWebAccessibleResources, &list_value)) {
2171 *error = ASCIIToUTF16(errors::kInvalidWebAccessibleResourcesList);
2172 return false;
2173 }
2174 for (size_t i = 0; i < list_value->GetSize(); ++i) {
2175 std::string relative_path;
2176 if (!list_value->GetString(i, &relative_path)) {
2177 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2178 errors::kInvalidWebAccessibleResource, base::IntToString(i));
2179 return false;
2180 }
2181 if (relative_path[0] != '/')
2182 relative_path = '/' + relative_path;
2183 web_accessible_resources_.insert(relative_path);
2184 }
2185 }
2186
2187 // Initialize page action (optional).
2188 DictionaryValue* page_action_value = NULL;
2189
2190 if (manifest_->HasKey(keys::kPageActions)) {
2191 ListValue* list_value = NULL;
2192 if (!manifest_->GetList(keys::kPageActions, &list_value)) {
2193 *error = ASCIIToUTF16(errors::kInvalidPageActionsList);
2194 return false;
2195 }
2196
2197 size_t list_value_length = list_value->GetSize();
2198
2199 if (list_value_length == 0u) {
2200 // A list with zero items is allowed, and is equivalent to not having
2201 // a page_actions key in the manifest. Don't set |page_action_value|.
2202 } else if (list_value_length == 1u) {
2203 if (!list_value->GetDictionary(0, &page_action_value)) {
2204 *error = ASCIIToUTF16(errors::kInvalidPageAction);
2205 return false;
2206 }
2207 } else { // list_value_length > 1u.
2208 *error = ASCIIToUTF16(errors::kInvalidPageActionsListSize);
2209 return false;
2210 }
2211 } else if (manifest_->HasKey(keys::kPageAction)) {
2212 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) {
2213 *error = ASCIIToUTF16(errors::kInvalidPageAction);
2214 return false;
2215 }
2216 }
2217
2218 // If page_action_value is not NULL, then there was a valid page action.
2219 if (page_action_value) {
2220 page_action_.reset(
2221 LoadExtensionActionHelper(page_action_value, error));
2222 if (!page_action_.get())
2223 return false; // Failed to parse page action definition.
2224 }
2225
2226 // Initialize browser action (optional).
2227 if (manifest_->HasKey(keys::kBrowserAction)) {
2228 DictionaryValue* browser_action_value = NULL;
2229 if (!manifest_->GetDictionary(keys::kBrowserAction,
2230 &browser_action_value)) {
2231 *error = ASCIIToUTF16(errors::kInvalidBrowserAction);
2232 return false;
2233 }
2234
2235 browser_action_.reset(
2236 LoadExtensionActionHelper(browser_action_value, error));
2237 if (!browser_action_.get())
2238 return false; // Failed to parse browser action definition.
2239 }
2240
2241 // Initialize file browser actions (optional).
2242 if (manifest_->HasKey(keys::kFileBrowserHandlers)) {
2243 ListValue* file_browser_handlers_value = NULL;
2244 if (!manifest_->GetList(keys::kFileBrowserHandlers,
2245 &file_browser_handlers_value)) {
2246 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
2247 return false;
2248 }
2249
2250 file_browser_handlers_.reset(
2251 LoadFileBrowserHandlers(file_browser_handlers_value, error));
2252 if (!file_browser_handlers_.get())
2253 return false; // Failed to parse file browser actions definition.
2254 }
2255
2256 // App isolation. 2819 // App isolation.
2257 if (api_permissions.count(ExtensionAPIPermission::kExperimental)) { 2820 if (api_permissions.count(ExtensionAPIPermission::kExperimental) &&
2258 if (is_app() && !LoadAppIsolation(error)) 2821 !LoadAppIsolation(error))
Yoyo Zhou 2012/03/01 01:17:25 This used to have an is_app check. Ideally this w
Yoyo Zhou 2012/03/02 20:20:07 Can you put the is_app check back here?
2259 return false; 2822 return false;
2260 } 2823
2261 2824 if (!LoadExtensionFeatures(flags, api_permissions, error))
2262 // Initialize options page url (optional). 2825 return false;
2263 if (manifest_->HasKey(keys::kOptionsPage)) { 2826
2264 std::string options_str; 2827 if (manifest_->HasKey(keys::kTheme) && !LoadThemeFeatures(error))
2265 if (!manifest_->GetString(keys::kOptionsPage, &options_str)) { 2828 return false;
2266 *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
2267 return false;
2268 }
2269
2270 if (is_hosted_app()) {
2271 // hosted apps require an absolute URL.
2272 GURL options_url(options_str);
2273 if (!options_url.is_valid() ||
2274 !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) {
2275 *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
2276 return false;
2277 }
2278 options_url_ = options_url;
2279 } else {
2280 GURL absolute(options_str);
2281 if (absolute.is_valid()) {
2282 *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
2283 return false;
2284 }
2285 options_url_ = GetResourceURL(options_str);
2286 if (!options_url_.is_valid()) {
2287 *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
2288 return false;
2289 }
2290 }
2291 }
2292
2293 if (!LoadBackgroundScripts(error))
2294 return false;
2295
2296 if (!LoadBackgroundPage(api_permissions, error))
2297 return false;
2298
2299 if (!LoadBackgroundPersistent(api_permissions, error))
2300 return false;
2301
2302 if (manifest_->HasKey(keys::kDefaultLocale)) {
2303 if (!manifest_->GetString(keys::kDefaultLocale, &default_locale_) ||
2304 !l10n_util::IsValidLocaleSyntax(default_locale_)) {
2305 *error = ASCIIToUTF16(errors::kInvalidDefaultLocale);
2306 return false;
2307 }
2308 }
2309
2310 // Chrome URL overrides (optional)
2311 if (manifest_->HasKey(keys::kChromeURLOverrides)) {
2312 DictionaryValue* overrides = NULL;
2313 if (!manifest_->GetDictionary(keys::kChromeURLOverrides, &overrides)) {
2314 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
2315 return false;
2316 }
2317
2318 // Validate that the overrides are all strings
2319 for (DictionaryValue::key_iterator iter = overrides->begin_keys();
2320 iter != overrides->end_keys(); ++iter) {
2321 std::string page = *iter;
2322 std::string val;
2323 // Restrict override pages to a list of supported URLs.
2324 if ((page != chrome::kChromeUINewTabHost &&
2325 #if defined(USE_VIRTUAL_KEYBOARD)
2326 page != chrome::kChromeUIKeyboardHost &&
2327 #endif
2328 #if defined(OS_CHROMEOS)
2329 page != chrome::kChromeUIActivationMessageHost &&
2330 #endif
2331 page != chrome::kChromeUIBookmarksHost &&
2332 page != chrome::kChromeUIHistoryHost
2333 #if defined(FILE_MANAGER_EXTENSION)
2334 &&
2335 !(location() == COMPONENT &&
2336 page == chrome::kChromeUIFileManagerHost)
2337 #endif
2338 ) ||
2339 !overrides->GetStringWithoutPathExpansion(*iter, &val)) {
2340 *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
2341 return false;
2342 }
2343 // Replace the entry with a fully qualified chrome-extension:// URL.
2344 chrome_url_overrides_[page] = GetResourceURL(val);
2345 }
2346
2347 // An extension may override at most one page.
2348 if (overrides->size() > 1) {
2349 *error = ASCIIToUTF16(errors::kMultipleOverrides);
2350 return false;
2351 }
2352 }
2353
2354 if (manifest_->HasKey(keys::kInputComponents)) {
2355 ListValue* list_value = NULL;
2356 if (!manifest_->GetList(keys::kInputComponents, &list_value)) {
2357 *error = ASCIIToUTF16(errors::kInvalidInputComponents);
2358 return false;
2359 }
2360
2361 for (size_t i = 0; i < list_value->GetSize(); ++i) {
2362 DictionaryValue* module_value = NULL;
2363 std::string name_str;
2364 InputComponentType type;
2365 std::string id_str;
2366 std::string description_str;
2367 std::string language_str;
2368 std::set<std::string> layouts;
2369 std::string shortcut_keycode_str;
2370 bool shortcut_alt = false;
2371 bool shortcut_ctrl = false;
2372 bool shortcut_shift = false;
2373
2374 if (!list_value->GetDictionary(i, &module_value)) {
2375 *error = ASCIIToUTF16(errors::kInvalidInputComponents);
2376 return false;
2377 }
2378
2379 // Get input_components[i].name.
2380 if (!module_value->GetString(keys::kName, &name_str)) {
2381 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2382 errors::kInvalidInputComponentName, base::IntToString(i));
2383 return false;
2384 }
2385
2386 // Get input_components[i].type.
2387 std::string type_str;
2388 if (module_value->GetString(keys::kType, &type_str)) {
2389 if (type_str == "ime") {
2390 type = INPUT_COMPONENT_TYPE_IME;
2391 } else if (type_str == "virtual_keyboard") {
2392 if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) {
2393 // Virtual Keyboards require the experimental flag.
2394 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2395 errors::kInvalidInputComponentType, base::IntToString(i));
2396 return false;
2397 }
2398 type = INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD;
2399 } else {
2400 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2401 errors::kInvalidInputComponentType, base::IntToString(i));
2402 return false;
2403 }
2404 } else {
2405 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2406 errors::kInvalidInputComponentType, base::IntToString(i));
2407 return false;
2408 }
2409
2410 // Get input_components[i].id.
2411 if (!module_value->GetString(keys::kId, &id_str)) {
2412 id_str = "";
2413 }
2414
2415 // Get input_components[i].description.
2416 if (!module_value->GetString(keys::kDescription, &description_str)) {
2417 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2418 errors::kInvalidInputComponentDescription, base::IntToString(i));
2419 return false;
2420 }
2421
2422 // Get input_components[i].language.
2423 if (!module_value->GetString(keys::kLanguage, &language_str)) {
2424 language_str = "";
2425 }
2426
2427 // Get input_components[i].layouts.
2428 ListValue* layouts_value = NULL;
2429 if (!module_value->GetList(keys::kLayouts, &layouts_value)) {
2430 *error = ASCIIToUTF16(errors::kInvalidInputComponentLayouts);
2431 return false;
2432 }
2433
2434 for (size_t j = 0; j < layouts_value->GetSize(); ++j) {
2435 std::string layout_name_str;
2436 if (!layouts_value->GetString(j, &layout_name_str)) {
2437 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2438 errors::kInvalidInputComponentLayoutName, base::IntToString(i),
2439 base::IntToString(j));
2440 return false;
2441 }
2442 layouts.insert(layout_name_str);
2443 }
2444
2445 if (module_value->HasKey(keys::kShortcutKey)) {
2446 DictionaryValue* shortcut_value = NULL;
2447 if (!module_value->GetDictionary(keys::kShortcutKey, &shortcut_value)) {
2448 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2449 errors::kInvalidInputComponentShortcutKey, base::IntToString(i));
2450 return false;
2451 }
2452
2453 // Get input_components[i].shortcut_keycode.
2454 if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
2455 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2456 errors::kInvalidInputComponentShortcutKeycode,
2457 base::IntToString(i));
2458 return false;
2459 }
2460
2461 // Get input_components[i].shortcut_alt.
2462 if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
2463 shortcut_alt = false;
2464 }
2465
2466 // Get input_components[i].shortcut_ctrl.
2467 if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
2468 shortcut_ctrl = false;
2469 }
2470
2471 // Get input_components[i].shortcut_shift.
2472 if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
2473 shortcut_shift = false;
2474 }
2475 }
2476
2477 input_components_.push_back(InputComponentInfo());
2478 input_components_.back().name = name_str;
2479 input_components_.back().type = type;
2480 input_components_.back().id = id_str;
2481 input_components_.back().description = description_str;
2482 input_components_.back().language = language_str;
2483 input_components_.back().layouts.insert(layouts.begin(), layouts.end());
2484 input_components_.back().shortcut_keycode = shortcut_keycode_str;
2485 input_components_.back().shortcut_alt = shortcut_alt;
2486 input_components_.back().shortcut_ctrl = shortcut_ctrl;
2487 input_components_.back().shortcut_shift = shortcut_shift;
2488 }
2489 }
2490
2491 if (manifest_->HasKey(keys::kOmnibox)) {
2492 if (!manifest_->GetString(keys::kOmniboxKeyword, &omnibox_keyword_) ||
2493 omnibox_keyword_.empty()) {
2494 *error = ASCIIToUTF16(errors::kInvalidOmniboxKeyword);
2495 return false;
2496 }
2497 }
2498
2499 if (manifest_->HasKey(keys::kContentSecurityPolicy)) {
2500 std::string content_security_policy;
2501 if (!manifest_->GetString(keys::kContentSecurityPolicy,
2502 &content_security_policy)) {
2503 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
2504 return false;
2505 }
2506 if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
2507 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
2508 return false;
2509 }
2510 if (manifest_version_ >= 2 &&
2511 !ContentSecurityPolicyIsSecure(content_security_policy)) {
2512 *error = ASCIIToUTF16(errors::kInvalidContentSecurityPolicy);
2513 return false;
2514 }
2515
2516 content_security_policy_ = content_security_policy;
2517 } else if (manifest_version_ >= 2) {
2518 // Manifest version 2 introduced a default Content-Security-Policy.
2519 // TODO(abarth): Should we continue to let extensions override the
2520 // default Content-Security-Policy?
2521 content_security_policy_ = kDefaultContentSecurityPolicy;
2522 CHECK(ContentSecurityPolicyIsSecure(content_security_policy_));
2523 }
2524
2525 // Initialize devtools page url (optional).
2526 if (manifest_->HasKey(keys::kDevToolsPage)) {
2527 std::string devtools_str;
2528 if (!manifest_->GetString(keys::kDevToolsPage, &devtools_str)) {
2529 *error = ASCIIToUTF16(errors::kInvalidDevToolsPage);
2530 return false;
2531 }
2532 devtools_url_ = GetResourceURL(devtools_str);
2533 }
2534
2535 // Initialize text-to-speech voices (optional).
2536 if (manifest_->HasKey(keys::kTtsEngine)) {
2537 DictionaryValue* tts_dict = NULL;
2538 if (!manifest_->GetDictionary(keys::kTtsEngine, &tts_dict)) {
2539 *error = ASCIIToUTF16(errors::kInvalidTts);
2540 return false;
2541 }
2542
2543 if (tts_dict->HasKey(keys::kTtsVoices)) {
2544 ListValue* tts_voices = NULL;
2545 if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
2546 *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
2547 return false;
2548 }
2549
2550 for (size_t i = 0; i < tts_voices->GetSize(); i++) {
2551 DictionaryValue* one_tts_voice = NULL;
2552 if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
2553 *error = ASCIIToUTF16(errors::kInvalidTtsVoices);
2554 return false;
2555 }
2556
2557 TtsVoice voice_data;
2558 if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
2559 if (!one_tts_voice->GetString(
2560 keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
2561 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName);
2562 return false;
2563 }
2564 }
2565 if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) {
2566 if (!one_tts_voice->GetString(
2567 keys::kTtsVoicesLang, &voice_data.lang) ||
2568 !l10n_util::IsValidLocaleSyntax(voice_data.lang)) {
2569 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesLang);
2570 return false;
2571 }
2572 }
2573 if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
2574 if (!one_tts_voice->GetString(
2575 keys::kTtsVoicesGender, &voice_data.gender) ||
2576 (voice_data.gender != keys::kTtsGenderMale &&
2577 voice_data.gender != keys::kTtsGenderFemale)) {
2578 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesGender);
2579 return false;
2580 }
2581 }
2582 if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) {
2583 ListValue* event_types_list;
2584 if (!one_tts_voice->GetList(
2585 keys::kTtsVoicesEventTypes, &event_types_list)) {
2586 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
2587 return false;
2588 }
2589 for (size_t i = 0; i < event_types_list->GetSize(); i++) {
2590 std::string event_type;
2591 if (!event_types_list->GetString(i, &event_type)) {
2592 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
2593 return false;
2594 }
2595 if (event_type != keys::kTtsVoicesEventTypeEnd &&
2596 event_type != keys::kTtsVoicesEventTypeError &&
2597 event_type != keys::kTtsVoicesEventTypeMarker &&
2598 event_type != keys::kTtsVoicesEventTypeSentence &&
2599 event_type != keys::kTtsVoicesEventTypeStart &&
2600 event_type != keys::kTtsVoicesEventTypeWord) {
2601 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
2602 return false;
2603 }
2604 if (voice_data.event_types.find(event_type) !=
2605 voice_data.event_types.end()) {
2606 *error = ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
2607 return false;
2608 }
2609 voice_data.event_types.insert(event_type);
2610 }
2611 }
2612
2613 tts_voices_.push_back(voice_data);
2614 }
2615 }
2616 }
2617
2618 // Initialize web intents (optional).
2619 if (!LoadWebIntentServices(error))
2620 return false;
2621
2622 // Initialize incognito behavior. Apps default to split mode, extensions
2623 // default to spanning.
2624 incognito_split_mode_ = is_app();
2625 if (manifest_->HasKey(keys::kIncognito)) {
2626 std::string value;
2627 if (!manifest_->GetString(keys::kIncognito, &value)) {
2628 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
2629 return false;
2630 }
2631 if (value == values::kIncognitoSpanning) {
2632 incognito_split_mode_ = false;
2633 } else if (value == values::kIncognitoSplit) {
2634 incognito_split_mode_ = true;
2635 } else {
2636 *error = ASCIIToUTF16(errors::kInvalidIncognitoBehavior);
2637 return false;
2638 }
2639 }
2640
2641 // Initialize offline-enabled status. Defaults to false.
2642 if (manifest_->HasKey(keys::kOfflineEnabled)) {
2643 if (!manifest_->GetBoolean(keys::kOfflineEnabled, &offline_enabled_)) {
2644 *error = ASCIIToUTF16(errors::kInvalidOfflineEnabled);
2645 return false;
2646 }
2647 }
2648
2649 // Initialize requirements (optional). Not actually persisted (they're only
2650 // used by the store), but still validated.
2651 if (manifest_->HasKey(keys::kRequirements)) {
2652 DictionaryValue* requirements_value = NULL;
2653 if (!manifest_->GetDictionary(keys::kRequirements, &requirements_value)) {
2654 *error = ASCIIToUTF16(errors::kInvalidRequirements);
2655 return false;
2656 }
2657
2658 for (DictionaryValue::key_iterator it = requirements_value->begin_keys();
2659 it != requirements_value->end_keys(); ++it) {
2660 DictionaryValue* requirement_value;
2661 if (!requirements_value->GetDictionaryWithoutPathExpansion(
2662 *it, &requirement_value)) {
2663 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
2664 errors::kInvalidRequirement, *it);
2665 return false;
2666 }
2667 }
2668 }
2669 2829
2670 if (HasMultipleUISurfaces()) { 2830 if (HasMultipleUISurfaces()) {
2671 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly); 2831 *error = ASCIIToUTF16(errors::kOneUISurfaceOnly);
2672 return false; 2832 return false;
2673 } 2833 }
2674 2834
2675 runtime_data_.SetActivePermissions(new ExtensionPermissionSet( 2835 runtime_data_.SetActivePermissions(new ExtensionPermissionSet(
2676 this, api_permissions, host_permissions)); 2836 this, api_permissions, host_permissions));
2677 required_permission_set_ = new ExtensionPermissionSet( 2837 required_permission_set_ = new ExtensionPermissionSet(
2678 this, api_permissions, host_permissions); 2838 this, api_permissions, host_permissions);
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
3068 // extension with options. All other menu items like uninstall have 3228 // extension with options. All other menu items like uninstall have
3069 // no sense for component extensions. 3229 // no sense for component extensions.
3070 return location() != Extension::COMPONENT; 3230 return location() != Extension::COMPONENT;
3071 } 3231 }
3072 3232
3073 bool Extension::CanSpecifyAPIPermission( 3233 bool Extension::CanSpecifyAPIPermission(
3074 const ExtensionAPIPermission* permission, 3234 const ExtensionAPIPermission* permission,
3075 string16* error) const { 3235 string16* error) const {
3076 if (location() == Extension::COMPONENT) 3236 if (location() == Extension::COMPONENT)
3077 return true; 3237 return true;
3078
3079 bool access_denied = false; 3238 bool access_denied = false;
3080 if (permission->HasWhitelist()) { 3239 if (permission->HasWhitelist()) {
3081 if (permission->IsWhitelisted(id())) 3240 if (permission->IsWhitelisted(id()))
3082 return true; 3241 return true;
3083 else 3242 else
3084 access_denied = true; 3243 access_denied = true;
3085 } else if (permission->is_component_only()) { 3244 } else if (permission->is_component_only()) {
3086 access_denied = true; 3245 access_denied = true;
3087 } 3246 }
3088 3247
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
3246 return SYNC_TYPE_APP; 3405 return SYNC_TYPE_APP;
3247 3406
3248 default: 3407 default:
3249 return SYNC_TYPE_NONE; 3408 return SYNC_TYPE_NONE;
3250 } 3409 }
3251 } 3410 }
3252 3411
3253 bool Extension::IsSyncable() const { 3412 bool Extension::IsSyncable() const {
3254 // TODO(akalin): Figure out if we need to allow some other types. 3413 // TODO(akalin): Figure out if we need to allow some other types.
3255 3414
3256 // We want to sync any extensions that are shown in the luancher because 3415 // We want to sync any extensions that are shown in the launcher because
3257 // their positions should sync. 3416 // their positions should sync.
3258 return location() == Extension::INTERNAL || 3417 return location() == Extension::INTERNAL ||
3259 ShouldDisplayInLauncher(); 3418 ShouldDisplayInLauncher();
3260 } 3419 }
3261 3420
3262 bool Extension::ShouldDisplayInLauncher() const { 3421 bool Extension::ShouldDisplayInLauncher() const {
3263 // All apps should be displayed on the NTP except for the Cloud Print App. 3422 // All apps should be displayed on the NTP except for the Cloud Print App.
3264 return is_app() && id() != extension_misc::kCloudPrintAppId; 3423 return is_app() && id() != extension_misc::kCloudPrintAppId;
3265 } 3424 }
3266 3425
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
3299 already_disabled(false), 3458 already_disabled(false),
3300 extension(extension) {} 3459 extension(extension) {}
3301 3460
3302 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 3461 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
3303 const Extension* extension, 3462 const Extension* extension,
3304 const ExtensionPermissionSet* permissions, 3463 const ExtensionPermissionSet* permissions,
3305 Reason reason) 3464 Reason reason)
3306 : reason(reason), 3465 : reason(reason),
3307 extension(extension), 3466 extension(extension),
3308 permissions(permissions) {} 3467 permissions(permissions) {}
OLDNEW
« chrome/common/extensions/extension.h ('K') | « chrome/common/extensions/extension.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698