| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 #include "chrome/common/extensions/features/feature.h" | 40 #include "chrome/common/extensions/features/feature.h" |
| 41 #include "chrome/common/extensions/manifest.h" | 41 #include "chrome/common/extensions/manifest.h" |
| 42 #include "chrome/common/extensions/manifest_handler.h" | 42 #include "chrome/common/extensions/manifest_handler.h" |
| 43 #include "chrome/common/extensions/manifest_handler_helpers.h" | 43 #include "chrome/common/extensions/manifest_handler_helpers.h" |
| 44 #include "chrome/common/extensions/manifest_url_handler.h" | 44 #include "chrome/common/extensions/manifest_url_handler.h" |
| 45 #include "chrome/common/extensions/permissions/api_permission_set.h" | 45 #include "chrome/common/extensions/permissions/api_permission_set.h" |
| 46 #include "chrome/common/extensions/permissions/permission_set.h" | 46 #include "chrome/common/extensions/permissions/permission_set.h" |
| 47 #include "chrome/common/extensions/permissions/permissions_info.h" | 47 #include "chrome/common/extensions/permissions/permissions_info.h" |
| 48 #include "chrome/common/extensions/user_script.h" | 48 #include "chrome/common/extensions/user_script.h" |
| 49 #include "chrome/common/url_constants.h" | 49 #include "chrome/common/url_constants.h" |
| 50 #include "crypto/sha2.h" | |
| 51 #include "extensions/common/constants.h" | 50 #include "extensions/common/constants.h" |
| 52 #include "extensions/common/error_utils.h" | 51 #include "extensions/common/error_utils.h" |
| 52 #include "extensions/common/id_util.h" |
| 53 #include "extensions/common/url_pattern_set.h" | 53 #include "extensions/common/url_pattern_set.h" |
| 54 #include "googleurl/src/url_util.h" | 54 #include "googleurl/src/url_util.h" |
| 55 #include "grit/chromium_strings.h" | 55 #include "grit/chromium_strings.h" |
| 56 #include "grit/theme_resources.h" | 56 #include "grit/theme_resources.h" |
| 57 #include "third_party/skia/include/core/SkBitmap.h" | 57 #include "third_party/skia/include/core/SkBitmap.h" |
| 58 #include "ui/base/l10n/l10n_util.h" | 58 #include "ui/base/l10n/l10n_util.h" |
| 59 | 59 |
| 60 #if defined(OS_WIN) | 60 #if defined(OS_WIN) |
| 61 #include "grit/generated_resources.h" | 61 #include "grit/generated_resources.h" |
| 62 #endif | 62 #endif |
| (...skipping 22 matching lines...) Expand all Loading... |
| 85 const char kKeyBeginFooterMarker[] = "-----END"; | 85 const char kKeyBeginFooterMarker[] = "-----END"; |
| 86 const char kKeyInfoEndMarker[] = "KEY-----"; | 86 const char kKeyInfoEndMarker[] = "KEY-----"; |
| 87 const char kPublic[] = "PUBLIC"; | 87 const char kPublic[] = "PUBLIC"; |
| 88 const char kPrivate[] = "PRIVATE"; | 88 const char kPrivate[] = "PRIVATE"; |
| 89 | 89 |
| 90 const int kRSAKeySize = 1024; | 90 const int kRSAKeySize = 1024; |
| 91 | 91 |
| 92 const char kDefaultSandboxedPageContentSecurityPolicy[] = | 92 const char kDefaultSandboxedPageContentSecurityPolicy[] = |
| 93 "sandbox allow-scripts allow-forms allow-popups"; | 93 "sandbox allow-scripts allow-forms allow-popups"; |
| 94 | 94 |
| 95 // Converts a normal hexadecimal string into the alphabet used by extensions. | |
| 96 // We use the characters 'a'-'p' instead of '0'-'f' to avoid ever having a | |
| 97 // completely numeric host, since some software interprets that as an IP | |
| 98 // address. | |
| 99 static void ConvertHexadecimalToIDAlphabet(std::string* id) { | |
| 100 for (size_t i = 0; i < id->size(); ++i) { | |
| 101 int val; | |
| 102 if (base::HexStringToInt(base::StringPiece(id->begin() + i, | |
| 103 id->begin() + i + 1), | |
| 104 &val)) { | |
| 105 (*id)[i] = val + 'a'; | |
| 106 } else { | |
| 107 (*id)[i] = 'a'; | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 // A singleton object containing global data needed by the extension objects. | 95 // A singleton object containing global data needed by the extension objects. |
| 113 class ExtensionConfig { | 96 class ExtensionConfig { |
| 114 public: | 97 public: |
| 115 static ExtensionConfig* GetInstance() { | 98 static ExtensionConfig* GetInstance() { |
| 116 return Singleton<ExtensionConfig>::get(); | 99 return Singleton<ExtensionConfig>::get(); |
| 117 } | 100 } |
| 118 | 101 |
| 119 Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; } | 102 Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; } |
| 120 | 103 |
| 121 private: | 104 private: |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 scoped_ptr<ActionInfo> LoadExtensionActionInfoHelper( | 173 scoped_ptr<ActionInfo> LoadExtensionActionInfoHelper( |
| 191 const Extension* extension, | 174 const Extension* extension, |
| 192 const DictionaryValue* extension_action, | 175 const DictionaryValue* extension_action, |
| 193 string16* error) { | 176 string16* error) { |
| 194 return manifest_handler_helpers::LoadActionInfo( | 177 return manifest_handler_helpers::LoadActionInfo( |
| 195 extension, extension_action, error); | 178 extension, extension_action, error); |
| 196 } | 179 } |
| 197 | 180 |
| 198 } // namespace | 181 } // namespace |
| 199 | 182 |
| 200 const base::FilePath::CharType Extension::kManifestFilename[] = | |
| 201 FILE_PATH_LITERAL("manifest.json"); | |
| 202 const base::FilePath::CharType Extension::kLocaleFolder[] = | |
| 203 FILE_PATH_LITERAL("_locales"); | |
| 204 const base::FilePath::CharType Extension::kMessagesFilename[] = | |
| 205 FILE_PATH_LITERAL("messages.json"); | |
| 206 const base::FilePath::CharType Extension::kPlatformSpecificFolder[] = | |
| 207 FILE_PATH_LITERAL("_platform_specific"); | |
| 208 | |
| 209 #if defined(OS_WIN) | 183 #if defined(OS_WIN) |
| 210 const char Extension::kExtensionRegistryPath[] = | 184 const char Extension::kExtensionRegistryPath[] = |
| 211 "Software\\Google\\Chrome\\Extensions"; | 185 "Software\\Google\\Chrome\\Extensions"; |
| 212 #endif | 186 #endif |
| 213 | 187 |
| 214 // first 16 bytes of SHA256 hashed public key. | |
| 215 const size_t Extension::kIdSize = 16; | |
| 216 | |
| 217 const char Extension::kMimeType[] = "application/x-chrome-extension"; | 188 const char Extension::kMimeType[] = "application/x-chrome-extension"; |
| 218 | 189 |
| 219 const int Extension::kValidWebExtentSchemes = | 190 const int Extension::kValidWebExtentSchemes = |
| 220 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS; | 191 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS; |
| 221 | 192 |
| 222 const int Extension::kValidHostPermissionSchemes = URLPattern::SCHEME_CHROMEUI | | 193 const int Extension::kValidHostPermissionSchemes = URLPattern::SCHEME_CHROMEUI | |
| 223 URLPattern::SCHEME_HTTP | | 194 URLPattern::SCHEME_HTTP | |
| 224 URLPattern::SCHEME_HTTPS | | 195 URLPattern::SCHEME_HTTPS | |
| 225 URLPattern::SCHEME_FILE | | 196 URLPattern::SCHEME_FILE | |
| 226 URLPattern::SCHEME_FTP; | 197 URLPattern::SCHEME_FTP; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 *utf8_error = UTF16ToUTF8(error); | 259 *utf8_error = UTF16ToUTF8(error); |
| 289 return NULL; | 260 return NULL; |
| 290 } | 261 } |
| 291 | 262 |
| 292 return extension; | 263 return extension; |
| 293 } | 264 } |
| 294 | 265 |
| 295 // static | 266 // static |
| 296 bool Extension::IdIsValid(const std::string& id) { | 267 bool Extension::IdIsValid(const std::string& id) { |
| 297 // Verify that the id is legal. | 268 // Verify that the id is legal. |
| 298 if (id.size() != (kIdSize * 2)) | 269 if (id.size() != (id_util::kIdSize * 2)) |
| 299 return false; | 270 return false; |
| 300 | 271 |
| 301 // We only support lowercase IDs, because IDs can be used as URL components | 272 // We only support lowercase IDs, because IDs can be used as URL components |
| 302 // (where GURL will lowercase it). | 273 // (where GURL will lowercase it). |
| 303 std::string temp = StringToLowerASCII(id); | 274 std::string temp = StringToLowerASCII(id); |
| 304 for (size_t i = 0; i < temp.size(); i++) | 275 for (size_t i = 0; i < temp.size(); i++) |
| 305 if (temp[i] < 'a' || temp[i] > 'p') | 276 if (temp[i] < 'a' || temp[i] > 'p') |
| 306 return false; | 277 return false; |
| 307 | 278 |
| 308 return true; | 279 return true; |
| 309 } | 280 } |
| 310 | 281 |
| 311 // static | 282 // static |
| 312 std::string Extension::GenerateIdForPath(const base::FilePath& path) { | |
| 313 base::FilePath new_path = Extension::MaybeNormalizePath(path); | |
| 314 std::string path_bytes = | |
| 315 std::string(reinterpret_cast<const char*>(new_path.value().data()), | |
| 316 new_path.value().size() * sizeof(base::FilePath::CharType)); | |
| 317 std::string id; | |
| 318 return GenerateId(path_bytes, &id) ? id : ""; | |
| 319 } | |
| 320 | |
| 321 // static | |
| 322 bool Extension::IsExtension(const base::FilePath& file_name) { | 283 bool Extension::IsExtension(const base::FilePath& file_name) { |
| 323 return file_name.MatchesExtension(chrome::kExtensionFileExtension); | 284 return file_name.MatchesExtension(chrome::kExtensionFileExtension); |
| 324 } | 285 } |
| 325 | 286 |
| 326 void Extension::GetBasicInfo(bool enabled, | 287 void Extension::GetBasicInfo(bool enabled, |
| 327 DictionaryValue* info) const { | 288 DictionaryValue* info) const { |
| 328 info->SetString(info_keys::kIdKey, id()); | 289 info->SetString(info_keys::kIdKey, id()); |
| 329 info->SetString(info_keys::kNameKey, name()); | 290 info->SetString(info_keys::kNameKey, name()); |
| 330 info->SetBoolean(info_keys::kEnabledKey, enabled); | 291 info->SetBoolean(info_keys::kEnabledKey, enabled); |
| 331 info->SetBoolean(info_keys::kOfflineEnabledKey, offline_enabled()); | 292 info->SetBoolean(info_keys::kOfflineEnabledKey, offline_enabled()); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 return base::Base64Decode(working, output); | 404 return base::Base64Decode(working, output); |
| 444 } | 405 } |
| 445 | 406 |
| 446 // static | 407 // static |
| 447 bool Extension::ProducePEM(const std::string& input, std::string* output) { | 408 bool Extension::ProducePEM(const std::string& input, std::string* output) { |
| 448 DCHECK(output); | 409 DCHECK(output); |
| 449 return (input.length() == 0) ? false : base::Base64Encode(input, output); | 410 return (input.length() == 0) ? false : base::Base64Encode(input, output); |
| 450 } | 411 } |
| 451 | 412 |
| 452 // static | 413 // static |
| 453 bool Extension::GenerateId(const std::string& input, std::string* output) { | |
| 454 DCHECK(output); | |
| 455 uint8 hash[Extension::kIdSize]; | |
| 456 crypto::SHA256HashString(input, hash, sizeof(hash)); | |
| 457 *output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash))); | |
| 458 ConvertHexadecimalToIDAlphabet(output); | |
| 459 | |
| 460 return true; | |
| 461 } | |
| 462 | |
| 463 // static | |
| 464 bool Extension::FormatPEMForFileOutput(const std::string& input, | 414 bool Extension::FormatPEMForFileOutput(const std::string& input, |
| 465 std::string* output, | 415 std::string* output, |
| 466 bool is_public) { | 416 bool is_public) { |
| 467 DCHECK(output); | 417 DCHECK(output); |
| 468 if (input.length() == 0) | 418 if (input.length() == 0) |
| 469 return false; | 419 return false; |
| 470 *output = ""; | 420 *output = ""; |
| 471 output->append(kKeyBeginHeaderMarker); | 421 output->append(kKeyBeginHeaderMarker); |
| 472 output->append(" "); | 422 output->append(" "); |
| 473 output->append(is_public ? kPublic : kPrivate); | 423 output->append(is_public ? kPublic : kPrivate); |
| (...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1182 int creation_flags, | 1132 int creation_flags, |
| 1183 string16* error) { | 1133 string16* error) { |
| 1184 if (!explicit_id.empty()) { | 1134 if (!explicit_id.empty()) { |
| 1185 manifest->set_extension_id(explicit_id); | 1135 manifest->set_extension_id(explicit_id); |
| 1186 return true; | 1136 return true; |
| 1187 } | 1137 } |
| 1188 | 1138 |
| 1189 if (manifest->HasKey(keys::kPublicKey)) { | 1139 if (manifest->HasKey(keys::kPublicKey)) { |
| 1190 std::string public_key; | 1140 std::string public_key; |
| 1191 std::string public_key_bytes; | 1141 std::string public_key_bytes; |
| 1192 std::string extension_id; | |
| 1193 if (!manifest->GetString(keys::kPublicKey, &public_key) || | 1142 if (!manifest->GetString(keys::kPublicKey, &public_key) || |
| 1194 !ParsePEMKeyBytes(public_key, &public_key_bytes) || | 1143 !ParsePEMKeyBytes(public_key, &public_key_bytes)) { |
| 1195 !GenerateId(public_key_bytes, &extension_id)) { | |
| 1196 *error = ASCIIToUTF16(errors::kInvalidKey); | 1144 *error = ASCIIToUTF16(errors::kInvalidKey); |
| 1197 return false; | 1145 return false; |
| 1198 } | 1146 } |
| 1147 std::string extension_id = id_util::GenerateId(public_key_bytes); |
| 1199 manifest->set_extension_id(extension_id); | 1148 manifest->set_extension_id(extension_id); |
| 1200 return true; | 1149 return true; |
| 1201 } | 1150 } |
| 1202 | 1151 |
| 1203 if (creation_flags & REQUIRE_KEY) { | 1152 if (creation_flags & REQUIRE_KEY) { |
| 1204 *error = ASCIIToUTF16(errors::kInvalidKey); | 1153 *error = ASCIIToUTF16(errors::kInvalidKey); |
| 1205 return false; | 1154 return false; |
| 1206 } else { | 1155 } else { |
| 1207 // If there is a path, we generate the ID from it. This is useful for | 1156 // If there is a path, we generate the ID from it. This is useful for |
| 1208 // development mode, because it keeps the ID stable across restarts and | 1157 // development mode, because it keeps the ID stable across restarts and |
| 1209 // reloading the extension. | 1158 // reloading the extension. |
| 1210 std::string extension_id = GenerateIdForPath(path); | 1159 std::string extension_id = id_util::GenerateIdForPath(path); |
| 1211 if (extension_id.empty()) { | 1160 if (extension_id.empty()) { |
| 1212 NOTREACHED() << "Could not create ID from path."; | 1161 NOTREACHED() << "Could not create ID from path."; |
| 1213 return false; | 1162 return false; |
| 1214 } | 1163 } |
| 1215 manifest->set_extension_id(extension_id); | 1164 manifest->set_extension_id(extension_id); |
| 1216 return true; | 1165 return true; |
| 1217 } | 1166 } |
| 1218 } | 1167 } |
| 1219 | 1168 |
| 1220 // static | |
| 1221 base::FilePath Extension::MaybeNormalizePath(const base::FilePath& path) { | |
| 1222 #if defined(OS_WIN) | |
| 1223 // Normalize any drive letter to upper-case. We do this for consistency with | |
| 1224 // net_utils::FilePathToFileURL(), which does the same thing, to make string | |
| 1225 // comparisons simpler. | |
| 1226 std::wstring path_str = path.value(); | |
| 1227 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' && | |
| 1228 path_str[1] == ':') | |
| 1229 path_str[0] += ('A' - 'a'); | |
| 1230 | |
| 1231 return base::FilePath(path_str); | |
| 1232 #else | |
| 1233 return path; | |
| 1234 #endif | |
| 1235 } | |
| 1236 | |
| 1237 bool Extension::LoadManagedModeFeatures(string16* error) { | 1169 bool Extension::LoadManagedModeFeatures(string16* error) { |
| 1238 if (!manifest_->HasKey(keys::kContentPack)) | 1170 if (!manifest_->HasKey(keys::kContentPack)) |
| 1239 return true; | 1171 return true; |
| 1240 const DictionaryValue* content_pack_value = NULL; | 1172 const DictionaryValue* content_pack_value = NULL; |
| 1241 if (!manifest_->GetDictionary(keys::kContentPack, &content_pack_value)) { | 1173 if (!manifest_->GetDictionary(keys::kContentPack, &content_pack_value)) { |
| 1242 *error = ASCIIToUTF16(errors::kInvalidContentPack); | 1174 *error = ASCIIToUTF16(errors::kInvalidContentPack); |
| 1243 return false; | 1175 return false; |
| 1244 } | 1176 } |
| 1245 | 1177 |
| 1246 if (!LoadManagedModeSites(content_pack_value, error)) | 1178 if (!LoadManagedModeSites(content_pack_value, error)) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1291 finished_parsing_manifest_(false), | 1223 finished_parsing_manifest_(false), |
| 1292 is_storage_isolated_(false), | 1224 is_storage_isolated_(false), |
| 1293 launch_container_(extension_misc::LAUNCH_TAB), | 1225 launch_container_(extension_misc::LAUNCH_TAB), |
| 1294 launch_width_(0), | 1226 launch_width_(0), |
| 1295 launch_height_(0), | 1227 launch_height_(0), |
| 1296 display_in_launcher_(true), | 1228 display_in_launcher_(true), |
| 1297 display_in_new_tab_page_(true), | 1229 display_in_new_tab_page_(true), |
| 1298 wants_file_access_(false), | 1230 wants_file_access_(false), |
| 1299 creation_flags_(0) { | 1231 creation_flags_(0) { |
| 1300 DCHECK(path.empty() || path.IsAbsolute()); | 1232 DCHECK(path.empty() || path.IsAbsolute()); |
| 1301 path_ = MaybeNormalizePath(path); | 1233 path_ = id_util::MaybeNormalizePath(path); |
| 1302 } | 1234 } |
| 1303 | 1235 |
| 1304 Extension::~Extension() { | 1236 Extension::~Extension() { |
| 1305 } | 1237 } |
| 1306 | 1238 |
| 1307 bool Extension::InitFromValue(int flags, string16* error) { | 1239 bool Extension::InitFromValue(int flags, string16* error) { |
| 1308 DCHECK(error); | 1240 DCHECK(error); |
| 1309 | 1241 |
| 1310 base::AutoLock auto_lock(runtime_data_lock_); | 1242 base::AutoLock auto_lock(runtime_data_lock_); |
| 1311 | 1243 |
| (...skipping 1182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2494 | 2426 |
| 2495 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 2427 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
| 2496 const Extension* extension, | 2428 const Extension* extension, |
| 2497 const PermissionSet* permissions, | 2429 const PermissionSet* permissions, |
| 2498 Reason reason) | 2430 Reason reason) |
| 2499 : reason(reason), | 2431 : reason(reason), |
| 2500 extension(extension), | 2432 extension(extension), |
| 2501 permissions(permissions) {} | 2433 permissions(permissions) {} |
| 2502 | 2434 |
| 2503 } // namespace extensions | 2435 } // namespace extensions |
| OLD | NEW |