OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/common/extensions/extension.h" | 5 #include "chrome/common/extensions/extension.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
14 #include "base/i18n/rtl.h" | 14 #include "base/i18n/rtl.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/memory/singleton.h" | 16 #include "base/memory/singleton.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/string16.h" | 18 #include "base/string16.h" |
19 #include "base/string_number_conversions.h" | 19 #include "base/string_number_conversions.h" |
20 #include "base/string_piece.h" | 20 #include "base/string_piece.h" |
| 21 #include "base/string_split.h" |
21 #include "base/string_util.h" | 22 #include "base/string_util.h" |
22 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
23 #include "base/values.h" | 24 #include "base/values.h" |
24 #include "base/version.h" | 25 #include "base/version.h" |
25 #include "crypto/sha2.h" | 26 #include "crypto/sha2.h" |
26 #include "chrome/common/chrome_constants.h" | 27 #include "chrome/common/chrome_constants.h" |
27 #include "chrome/common/chrome_switches.h" | 28 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/chrome_version_info.h" | 29 #include "chrome/common/chrome_version_info.h" |
29 #include "chrome/common/extensions/csp_validator.h" | 30 #include "chrome/common/extensions/csp_validator.h" |
30 #include "chrome/common/extensions/extension_action.h" | 31 #include "chrome/common/extensions/extension_action.h" |
31 #include "chrome/common/extensions/extension_constants.h" | 32 #include "chrome/common/extensions/extension_constants.h" |
32 #include "chrome/common/extensions/extension_error_utils.h" | 33 #include "chrome/common/extensions/extension_error_utils.h" |
33 #include "chrome/common/extensions/extension_resource.h" | 34 #include "chrome/common/extensions/extension_resource.h" |
34 #include "chrome/common/extensions/file_browser_handler.h" | 35 #include "chrome/common/extensions/file_browser_handler.h" |
35 #include "chrome/common/extensions/manifest.h" | 36 #include "chrome/common/extensions/manifest.h" |
36 #include "chrome/common/extensions/user_script.h" | 37 #include "chrome/common/extensions/user_script.h" |
37 #include "chrome/common/url_constants.h" | 38 #include "chrome/common/url_constants.h" |
38 #include "googleurl/src/url_util.h" | 39 #include "googleurl/src/url_util.h" |
39 #include "grit/chromium_strings.h" | 40 #include "grit/chromium_strings.h" |
40 #include "grit/generated_resources.h" | 41 #include "grit/generated_resources.h" |
41 #include "grit/theme_resources.h" | 42 #include "grit/theme_resources.h" |
42 #include "net/base/registry_controlled_domain.h" | 43 #include "net/base/registry_controlled_domain.h" |
43 #include "third_party/skia/include/core/SkBitmap.h" | 44 #include "third_party/skia/include/core/SkBitmap.h" |
| 45 #include "ui/base/keycodes/keyboard_codes.h" |
44 #include "ui/base/l10n/l10n_util.h" | 46 #include "ui/base/l10n/l10n_util.h" |
45 #include "ui/base/resource/resource_bundle.h" | 47 #include "ui/base/resource/resource_bundle.h" |
46 #include "webkit/glue/image_decoder.h" | 48 #include "webkit/glue/image_decoder.h" |
47 #include "webkit/glue/web_intent_service_data.h" | 49 #include "webkit/glue/web_intent_service_data.h" |
48 | 50 |
49 namespace keys = extension_manifest_keys; | 51 namespace keys = extension_manifest_keys; |
50 namespace values = extension_manifest_values; | 52 namespace values = extension_manifest_values; |
51 namespace errors = extension_manifest_errors; | 53 namespace errors = extension_manifest_errors; |
52 | 54 |
53 using extensions::csp_validator::ContentSecurityPolicyIsLegal; | 55 using extensions::csp_validator::ContentSecurityPolicyIsLegal; |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 shortcut_alt(false), | 213 shortcut_alt(false), |
212 shortcut_ctrl(false), | 214 shortcut_ctrl(false), |
213 shortcut_shift(false) { | 215 shortcut_shift(false) { |
214 } | 216 } |
215 | 217 |
216 Extension::InputComponentInfo::~InputComponentInfo() {} | 218 Extension::InputComponentInfo::~InputComponentInfo() {} |
217 | 219 |
218 Extension::TtsVoice::TtsVoice() {} | 220 Extension::TtsVoice::TtsVoice() {} |
219 Extension::TtsVoice::~TtsVoice() {} | 221 Extension::TtsVoice::~TtsVoice() {} |
220 | 222 |
| 223 Extension::ExtensionKeybinding::ExtensionKeybinding() {} |
| 224 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} |
| 225 |
| 226 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, |
| 227 const std::string& command_name, |
| 228 int index, |
| 229 string16* error) { |
| 230 DCHECK(!command_name.empty()); |
| 231 std::string key_binding; |
| 232 if (!command->GetString(keys::kKey, &key_binding) || |
| 233 key_binding.empty()) { |
| 234 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 235 errors::kInvalidKeyBinding, |
| 236 base::IntToString(index), |
| 237 "Missing"); |
| 238 return false; |
| 239 } |
| 240 |
| 241 std::string original_keybinding = key_binding; |
| 242 // Normalize '-' to '+'. |
| 243 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+"); |
| 244 // Remove all spaces. |
| 245 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", ""); |
| 246 // And finally, lower-case it. |
| 247 key_binding = StringToLowerASCII(key_binding); |
| 248 |
| 249 std::vector<std::string> tokens; |
| 250 base::SplitString(key_binding, '+', &tokens); |
| 251 if (tokens.size() < 2 || tokens.size() > 3) { |
| 252 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 253 errors::kInvalidKeyBinding, |
| 254 base::IntToString(index), |
| 255 original_keybinding); |
| 256 return false; |
| 257 } |
| 258 |
| 259 // Now, parse it into an accelerator. |
| 260 bool ctrl = false; |
| 261 bool alt = false; |
| 262 bool shift = false; |
| 263 ui::KeyboardCode key = ui::VKEY_UNKNOWN; |
| 264 for (size_t i = 0; i < tokens.size(); i++) { |
| 265 if (tokens[i] == "ctrl") { |
| 266 ctrl = true; |
| 267 } else if (tokens[i] == "alt") { |
| 268 alt = true; |
| 269 } else if (tokens[i] == "shift") { |
| 270 shift = true; |
| 271 } else if (tokens[i].size() == 1 && |
| 272 base::ToUpperASCII(tokens[i][0]) >= ui::VKEY_A && |
| 273 base::ToUpperASCII(tokens[i][0]) <= ui::VKEY_Z) { |
| 274 if (key != ui::VKEY_UNKNOWN) { |
| 275 // Multiple key assignments. |
| 276 key = ui::VKEY_UNKNOWN; |
| 277 break; |
| 278 } |
| 279 |
| 280 key = static_cast<ui::KeyboardCode>( |
| 281 ui::VKEY_A + (base::ToUpperASCII(tokens[i][0]) - ui::VKEY_A)); |
| 282 } else { |
| 283 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 284 errors::kInvalidKeyBinding, |
| 285 base::IntToString(index), |
| 286 original_keybinding); |
| 287 return false; |
| 288 } |
| 289 } |
| 290 |
| 291 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not |
| 292 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: |
| 293 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. |
| 294 if (key == ui::VKEY_UNKNOWN || (ctrl == true && alt == true)) { |
| 295 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 296 errors::kInvalidKeyBinding, |
| 297 base::IntToString(index), |
| 298 original_keybinding); |
| 299 return false; |
| 300 } |
| 301 |
| 302 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); |
| 303 |
| 304 if (command_name != |
| 305 extension_manifest_values::kPageActionKeybindingEvent && |
| 306 command_name != |
| 307 extension_manifest_values::kBrowserActionKeybindingEvent) { |
| 308 if (!command->GetString(keys::kDescription, &description_) || |
| 309 description_.empty()) { |
| 310 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 311 errors::kInvalidKeyBindingDescription, |
| 312 base::IntToString(index)); |
| 313 return false; |
| 314 } |
| 315 } |
| 316 |
| 317 command_name_ = command_name; |
| 318 return true; |
| 319 } |
| 320 |
221 // | 321 // |
222 // Extension | 322 // Extension |
223 // | 323 // |
224 | 324 |
225 // static | 325 // static |
226 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 326 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
227 Location location, | 327 Location location, |
228 const DictionaryValue& value, | 328 const DictionaryValue& value, |
229 int flags, | 329 int flags, |
230 std::string* utf8_error) { | 330 std::string* utf8_error) { |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 errors::kInvalidURLPatternError, filter); | 950 errors::kInvalidURLPatternError, filter); |
851 return NULL; | 951 return NULL; |
852 } | 952 } |
853 result->AddPattern(pattern); | 953 result->AddPattern(pattern); |
854 } | 954 } |
855 | 955 |
856 std::string default_icon; | 956 std::string default_icon; |
857 // Read the file browser action |default_icon| (optional). | 957 // Read the file browser action |default_icon| (optional). |
858 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { | 958 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { |
859 if (!file_browser_handler->GetString( | 959 if (!file_browser_handler->GetString( |
860 keys::kPageActionDefaultIcon,&default_icon) || | 960 keys::kPageActionDefaultIcon, &default_icon) || |
861 default_icon.empty()) { | 961 default_icon.empty()) { |
862 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | 962 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); |
863 return NULL; | 963 return NULL; |
864 } | 964 } |
865 result->set_icon_path(default_icon); | 965 result->set_icon_path(default_icon); |
866 } | 966 } |
867 | 967 |
868 return result.release(); | 968 return result.release(); |
869 } | 969 } |
870 | 970 |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1151 *error = ASCIIToUTF16(errors::kInvalidIntent); | 1251 *error = ASCIIToUTF16(errors::kInvalidIntent); |
1152 return false; | 1252 return false; |
1153 } | 1253 } |
1154 service.action = UTF8ToUTF16(*iter); | 1254 service.action = UTF8ToUTF16(*iter); |
1155 | 1255 |
1156 ListValue* mime_types = NULL; | 1256 ListValue* mime_types = NULL; |
1157 if (!one_service->HasKey(keys::kIntentType) || | 1257 if (!one_service->HasKey(keys::kIntentType) || |
1158 !one_service->GetList(keys::kIntentType, &mime_types) || | 1258 !one_service->GetList(keys::kIntentType, &mime_types) || |
1159 mime_types->GetSize() == 0) { | 1259 mime_types->GetSize() == 0) { |
1160 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1260 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
1161 errors::kInvalidIntentType,*iter); | 1261 errors::kInvalidIntentType, *iter); |
1162 return false; | 1262 return false; |
1163 } | 1263 } |
1164 | 1264 |
1165 if (one_service->HasKey(keys::kIntentPath)) { | 1265 if (one_service->HasKey(keys::kIntentPath)) { |
1166 if (!one_service->GetString(keys::kIntentPath, &value)) { | 1266 if (!one_service->GetString(keys::kIntentPath, &value)) { |
1167 *error = ASCIIToUTF16(errors::kInvalidIntentPath); | 1267 *error = ASCIIToUTF16(errors::kInvalidIntentPath); |
1168 return false; | 1268 return false; |
1169 } | 1269 } |
1170 if (is_hosted_app()) { | 1270 if (is_hosted_app()) { |
1171 // Hosted apps require an absolute URL for intents. | 1271 // Hosted apps require an absolute URL for intents. |
1172 GURL service_url(value); | 1272 GURL service_url(value); |
1173 if (!service_url.is_valid() || | 1273 if (!service_url.is_valid() || |
1174 !(web_extent().MatchesURL(service_url))) { | 1274 !(web_extent().MatchesURL(service_url))) { |
1175 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1275 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
1176 errors::kInvalidIntentPageInHostedApp,*iter); | 1276 errors::kInvalidIntentPageInHostedApp, *iter); |
1177 return false; | 1277 return false; |
1178 } | 1278 } |
1179 service.service_url = service_url; | 1279 service.service_url = service_url; |
1180 } else { | 1280 } else { |
1181 // We do not allow absolute intent URLs in non-hosted apps. | 1281 // We do not allow absolute intent URLs in non-hosted apps. |
1182 if (GURL(value).is_valid()) { | 1282 if (GURL(value).is_valid()) { |
1183 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | 1283 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( |
1184 errors::kCannotAccessPage,value.c_str()); | 1284 errors::kCannotAccessPage, value.c_str()); |
1185 return false; | 1285 return false; |
1186 } | 1286 } |
1187 service.service_url = GetResourceURL(value); | 1287 service.service_url = GetResourceURL(value); |
1188 } | 1288 } |
1189 } | 1289 } |
1190 | 1290 |
1191 if (one_service->HasKey(keys::kIntentTitle) && | 1291 if (one_service->HasKey(keys::kIntentTitle) && |
1192 !one_service->GetString(keys::kIntentTitle, &service.title)) { | 1292 !one_service->GetString(keys::kIntentTitle, &service.title)) { |
1193 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | 1293 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); |
1194 return false; | 1294 return false; |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1708 minimum_version_string); | 1808 minimum_version_string); |
1709 return false; | 1809 return false; |
1710 } | 1810 } |
1711 } | 1811 } |
1712 | 1812 |
1713 // Initialize converted_from_user_script (if present) | 1813 // Initialize converted_from_user_script (if present) |
1714 if (manifest->HasKey(keys::kConvertedFromUserScript)) | 1814 if (manifest->HasKey(keys::kConvertedFromUserScript)) |
1715 manifest->GetBoolean(keys::kConvertedFromUserScript, | 1815 manifest->GetBoolean(keys::kConvertedFromUserScript, |
1716 &converted_from_user_script_); | 1816 &converted_from_user_script_); |
1717 | 1817 |
| 1818 // Initialize commands (if present). |
| 1819 if (manifest->HasKey(keys::kCommands)) { |
| 1820 DictionaryValue* commands = NULL; |
| 1821 if (!manifest->GetDictionary(keys::kCommands, &commands)) { |
| 1822 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); |
| 1823 return false; |
| 1824 } |
| 1825 |
| 1826 int command_index = 0; |
| 1827 for (DictionaryValue::key_iterator iter = commands->begin_keys(); |
| 1828 iter != commands->end_keys(); ++iter) { |
| 1829 ++command_index; |
| 1830 |
| 1831 DictionaryValue* command = NULL; |
| 1832 if (!commands->GetDictionary(*iter, &command)) { |
| 1833 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1834 errors::kInvalidKeyBindingDictionary, |
| 1835 base::IntToString(command_index)); |
| 1836 return false; |
| 1837 } |
| 1838 |
| 1839 ExtensionKeybinding binding; |
| 1840 if (!binding.Parse(command, *iter, command_index, error)) |
| 1841 return false; // |error| already set. |
| 1842 |
| 1843 commands_.push_back(binding); |
| 1844 } |
| 1845 } |
| 1846 |
1718 // Initialize icons (if present). | 1847 // Initialize icons (if present). |
1719 if (manifest->HasKey(keys::kIcons)) { | 1848 if (manifest->HasKey(keys::kIcons)) { |
1720 DictionaryValue* icons_value = NULL; | 1849 DictionaryValue* icons_value = NULL; |
1721 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { | 1850 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { |
1722 *error = ASCIIToUTF16(errors::kInvalidIcons); | 1851 *error = ASCIIToUTF16(errors::kInvalidIcons); |
1723 return false; | 1852 return false; |
1724 } | 1853 } |
1725 | 1854 |
1726 for (size_t i = 0; i < arraysize(kIconSizes); ++i) { | 1855 for (size_t i = 0; i < arraysize(kIconSizes); ++i) { |
1727 std::string key = base::IntToString(kIconSizes[i]); | 1856 std::string key = base::IntToString(kIconSizes[i]); |
(...skipping 1137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2865 | 2994 |
2866 if (permission->id() == ExtensionAPIPermission::kExperimental) { | 2995 if (permission->id() == ExtensionAPIPermission::kExperimental) { |
2867 if (!CanSpecifyExperimentalPermission()) { | 2996 if (!CanSpecifyExperimentalPermission()) { |
2868 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); | 2997 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); |
2869 return false; | 2998 return false; |
2870 } | 2999 } |
2871 } | 3000 } |
2872 | 3001 |
2873 bool supports_type = false; | 3002 bool supports_type = false; |
2874 switch (GetType()) { | 3003 switch (GetType()) { |
2875 case TYPE_USER_SCRIPT: // Pass through. | 3004 case TYPE_USER_SCRIPT: // Pass through. |
2876 case TYPE_EXTENSION: | 3005 case TYPE_EXTENSION: |
2877 supports_type = permission->supports_extensions(); | 3006 supports_type = permission->supports_extensions(); |
2878 break; | 3007 break; |
2879 case TYPE_HOSTED_APP: | 3008 case TYPE_HOSTED_APP: |
2880 supports_type = permission->supports_hosted_apps(); | 3009 supports_type = permission->supports_hosted_apps(); |
2881 break; | 3010 break; |
2882 case TYPE_PACKAGED_APP: | 3011 case TYPE_PACKAGED_APP: |
2883 supports_type = permission->supports_packaged_apps(); | 3012 supports_type = permission->supports_packaged_apps(); |
2884 break; | 3013 break; |
2885 case TYPE_PLATFORM_APP: | 3014 case TYPE_PLATFORM_APP: |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3021 } | 3150 } |
3022 } | 3151 } |
3023 | 3152 |
3024 bool Extension::IsSyncable() const { | 3153 bool Extension::IsSyncable() const { |
3025 // TODO(akalin): Figure out if we need to allow some other types. | 3154 // TODO(akalin): Figure out if we need to allow some other types. |
3026 | 3155 |
3027 // We want to sync any extensions that are shown in the luancher because | 3156 // We want to sync any extensions that are shown in the luancher because |
3028 // their positions should sync. | 3157 // their positions should sync. |
3029 return location_ == Extension::INTERNAL || | 3158 return location_ == Extension::INTERNAL || |
3030 ShouldDisplayInLauncher(); | 3159 ShouldDisplayInLauncher(); |
3031 | |
3032 } | 3160 } |
3033 | 3161 |
3034 bool Extension::ShouldDisplayInLauncher() const { | 3162 bool Extension::ShouldDisplayInLauncher() const { |
3035 // All apps should be displayed on the NTP except for the Cloud Print App. | 3163 // All apps should be displayed on the NTP except for the Cloud Print App. |
3036 return is_app() && id() != extension_misc::kCloudPrintAppId; | 3164 return is_app() && id() != extension_misc::kCloudPrintAppId; |
3037 } | 3165 } |
3038 | 3166 |
3039 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, | 3167 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, |
3040 const std::string& id, | 3168 const std::string& id, |
3041 const FilePath& path, | 3169 const FilePath& path, |
(...skipping 29 matching lines...) Expand all Loading... |
3071 already_disabled(false), | 3199 already_disabled(false), |
3072 extension(extension) {} | 3200 extension(extension) {} |
3073 | 3201 |
3074 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3202 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
3075 const Extension* extension, | 3203 const Extension* extension, |
3076 const ExtensionPermissionSet* permissions, | 3204 const ExtensionPermissionSet* permissions, |
3077 Reason reason) | 3205 Reason reason) |
3078 : reason(reason), | 3206 : reason(reason), |
3079 extension(extension), | 3207 extension(extension), |
3080 permissions(permissions) {} | 3208 permissions(permissions) {} |
OLD | NEW |