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_l10n_util.h" | 34 #include "chrome/common/extensions/extension_l10n_util.h" |
34 #include "chrome/common/extensions/extension_resource.h" | 35 #include "chrome/common/extensions/extension_resource.h" |
35 #include "chrome/common/extensions/file_browser_handler.h" | 36 #include "chrome/common/extensions/file_browser_handler.h" |
36 #include "chrome/common/extensions/manifest.h" | 37 #include "chrome/common/extensions/manifest.h" |
37 #include "chrome/common/extensions/user_script.h" | 38 #include "chrome/common/extensions/user_script.h" |
38 #include "chrome/common/url_constants.h" | 39 #include "chrome/common/url_constants.h" |
39 #include "googleurl/src/url_util.h" | 40 #include "googleurl/src/url_util.h" |
40 #include "grit/chromium_strings.h" | 41 #include "grit/chromium_strings.h" |
41 #include "grit/generated_resources.h" | 42 #include "grit/generated_resources.h" |
42 #include "grit/theme_resources.h" | 43 #include "grit/theme_resources.h" |
43 #include "net/base/registry_controlled_domain.h" | 44 #include "net/base/registry_controlled_domain.h" |
44 #include "third_party/skia/include/core/SkBitmap.h" | 45 #include "third_party/skia/include/core/SkBitmap.h" |
46 #include "ui/base/keycodes/keyboard_codes.h" | |
45 #include "ui/base/l10n/l10n_util.h" | 47 #include "ui/base/l10n/l10n_util.h" |
46 #include "ui/base/resource/resource_bundle.h" | 48 #include "ui/base/resource/resource_bundle.h" |
47 #include "webkit/glue/image_decoder.h" | 49 #include "webkit/glue/image_decoder.h" |
48 #include "webkit/glue/web_intent_service_data.h" | 50 #include "webkit/glue/web_intent_service_data.h" |
49 | 51 |
50 namespace keys = extension_manifest_keys; | 52 namespace keys = extension_manifest_keys; |
51 namespace values = extension_manifest_values; | 53 namespace values = extension_manifest_values; |
52 namespace errors = extension_manifest_errors; | 54 namespace errors = extension_manifest_errors; |
53 | 55 |
54 using extensions::csp_validator::ContentSecurityPolicyIsLegal; | 56 using extensions::csp_validator::ContentSecurityPolicyIsLegal; |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 shortcut_alt(false), | 214 shortcut_alt(false), |
213 shortcut_ctrl(false), | 215 shortcut_ctrl(false), |
214 shortcut_shift(false) { | 216 shortcut_shift(false) { |
215 } | 217 } |
216 | 218 |
217 Extension::InputComponentInfo::~InputComponentInfo() {} | 219 Extension::InputComponentInfo::~InputComponentInfo() {} |
218 | 220 |
219 Extension::TtsVoice::TtsVoice() {} | 221 Extension::TtsVoice::TtsVoice() {} |
220 Extension::TtsVoice::~TtsVoice() {} | 222 Extension::TtsVoice::~TtsVoice() {} |
221 | 223 |
224 Extension::ExtensionKeybinding::ExtensionKeybinding() {} | |
225 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} | |
226 | |
227 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, | |
228 const std::string& command_name, | |
229 int index, | |
230 string16* error) { | |
231 DCHECK(!command_name.empty()); | |
232 std::string key_binding; | |
233 if (!command->GetString(keys::kKey, &key_binding) || | |
234 key_binding.empty()) { | |
235 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
236 errors::kInvalidKeyBinding, | |
237 base::IntToString(index), | |
238 "Missing"); | |
239 return false; | |
240 } | |
241 | |
242 std::string original_keybinding = key_binding; | |
243 // Normalize '-' to '+'. | |
244 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+"); | |
245 // Remove all spaces. | |
246 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", ""); | |
247 // And finally, lower-case it. | |
248 key_binding = StringToLowerASCII(key_binding); | |
249 | |
250 std::vector<std::string> tokens; | |
251 base::SplitString(key_binding, '+', &tokens); | |
252 if (tokens.size() < 2 || tokens.size() > 3) { | |
253 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
254 errors::kInvalidKeyBinding, | |
255 base::IntToString(index), | |
256 original_keybinding); | |
257 return false; | |
258 } | |
259 | |
260 // Now, parse it into an accelerator. | |
261 bool ctrl = false; | |
262 bool alt = false; | |
263 bool shift = false; | |
264 ui::KeyboardCode key = ui::VKEY_UNKNOWN; | |
265 for (size_t i = 0; i < tokens.size(); i++) { | |
266 if (tokens[i] == "ctrl") { | |
267 ctrl = true; | |
268 } else if (tokens[i] == "alt") { | |
269 alt = true; | |
270 } else if (tokens[i] == "shift") { | |
271 shift = true; | |
272 } else if (tokens[i].size() == 1 && | |
273 base::ToUpperASCII(tokens[i][0]) >= ui::VKEY_A && | |
Matt Perry
2012/02/22 23:59:42
Just use 'a' so you don't have to uppercase it. Al
| |
274 base::ToUpperASCII(tokens[i][0]) <= ui::VKEY_Z) { | |
275 if (key != ui::VKEY_UNKNOWN) { | |
276 // Multiple key assignments. | |
277 key = ui::VKEY_UNKNOWN; | |
278 break; | |
279 } | |
280 | |
281 key = static_cast<ui::KeyboardCode>( | |
282 ui::VKEY_A + (base::ToUpperASCII(tokens[i][0]) - ui::VKEY_A)); | |
Matt Perry
2012/02/22 23:59:42
see above, second VKEY_A => 'a'
| |
283 } else { | |
284 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
285 errors::kInvalidKeyBinding, | |
286 base::IntToString(index), | |
287 original_keybinding); | |
288 return false; | |
289 } | |
290 } | |
291 | |
292 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not | |
293 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: | |
294 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. | |
295 if (key == ui::VKEY_UNKNOWN || ctrl == true && alt == true) { | |
Matt Perry
2012/02/22 23:59:42
Please add parens around (ctrl == true && alt == t
| |
296 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
297 errors::kInvalidKeyBinding, | |
298 base::IntToString(index), | |
299 original_keybinding); | |
300 return false; | |
301 } | |
302 | |
303 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); | |
304 | |
305 if (command_name != | |
306 extension_manifest_values::kPageActionKeybindingEvent && | |
307 command_name != | |
308 extension_manifest_values::kBrowserActionKeybindingEvent) { | |
309 if (!command->GetString(keys::kDescription, &description_) || | |
310 description_.empty()) { | |
311 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
312 errors::kInvalidKeyBindingDescription, | |
313 base::IntToString(index)); | |
314 return false; | |
315 } | |
316 } | |
317 | |
318 command_name_ = command_name; | |
319 return true; | |
320 } | |
321 | |
222 // | 322 // |
223 // Extension | 323 // Extension |
224 // | 324 // |
225 | 325 |
226 // static | 326 // static |
227 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 327 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
228 Location location, | 328 Location location, |
229 const DictionaryValue& value, | 329 const DictionaryValue& value, |
230 int flags, | 330 int flags, |
231 std::string* utf8_error) { | 331 std::string* utf8_error) { |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
851 errors::kInvalidURLPatternError, filter); | 951 errors::kInvalidURLPatternError, filter); |
852 return NULL; | 952 return NULL; |
853 } | 953 } |
854 result->AddPattern(pattern); | 954 result->AddPattern(pattern); |
855 } | 955 } |
856 | 956 |
857 std::string default_icon; | 957 std::string default_icon; |
858 // Read the file browser action |default_icon| (optional). | 958 // Read the file browser action |default_icon| (optional). |
859 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { | 959 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { |
860 if (!file_browser_handler->GetString( | 960 if (!file_browser_handler->GetString( |
861 keys::kPageActionDefaultIcon,&default_icon) || | 961 keys::kPageActionDefaultIcon, &default_icon) || |
862 default_icon.empty()) { | 962 default_icon.empty()) { |
863 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | 963 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); |
864 return NULL; | 964 return NULL; |
865 } | 965 } |
866 result->set_icon_path(default_icon); | 966 result->set_icon_path(default_icon); |
867 } | 967 } |
868 | 968 |
869 return result.release(); | 969 return result.release(); |
870 } | 970 } |
871 | 971 |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1155 *error = ASCIIToUTF16(errors::kInvalidIntent); | 1255 *error = ASCIIToUTF16(errors::kInvalidIntent); |
1156 return false; | 1256 return false; |
1157 } | 1257 } |
1158 service.action = UTF8ToUTF16(*iter); | 1258 service.action = UTF8ToUTF16(*iter); |
1159 | 1259 |
1160 ListValue* mime_types = NULL; | 1260 ListValue* mime_types = NULL; |
1161 if (!one_service->HasKey(keys::kIntentType) || | 1261 if (!one_service->HasKey(keys::kIntentType) || |
1162 !one_service->GetList(keys::kIntentType, &mime_types) || | 1262 !one_service->GetList(keys::kIntentType, &mime_types) || |
1163 mime_types->GetSize() == 0) { | 1263 mime_types->GetSize() == 0) { |
1164 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1264 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
1165 errors::kInvalidIntentType,*iter); | 1265 errors::kInvalidIntentType, *iter); |
1166 return false; | 1266 return false; |
1167 } | 1267 } |
1168 | 1268 |
1169 if (one_service->HasKey(keys::kIntentPath)) { | 1269 if (one_service->HasKey(keys::kIntentPath)) { |
1170 if (!one_service->GetString(keys::kIntentPath, &value)) { | 1270 if (!one_service->GetString(keys::kIntentPath, &value)) { |
1171 *error = ASCIIToUTF16(errors::kInvalidIntentPath); | 1271 *error = ASCIIToUTF16(errors::kInvalidIntentPath); |
1172 return false; | 1272 return false; |
1173 } | 1273 } |
1174 if (is_hosted_app()) { | 1274 if (is_hosted_app()) { |
1175 // Hosted apps require an absolute URL for intents. | 1275 // Hosted apps require an absolute URL for intents. |
1176 GURL service_url(value); | 1276 GURL service_url(value); |
1177 if (!service_url.is_valid() || | 1277 if (!service_url.is_valid() || |
1178 !(web_extent().MatchesURL(service_url))) { | 1278 !(web_extent().MatchesURL(service_url))) { |
1179 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1279 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
1180 errors::kInvalidIntentPageInHostedApp,*iter); | 1280 errors::kInvalidIntentPageInHostedApp, *iter); |
1181 return false; | 1281 return false; |
1182 } | 1282 } |
1183 service.service_url = service_url; | 1283 service.service_url = service_url; |
1184 } else { | 1284 } else { |
1185 // We do not allow absolute intent URLs in non-hosted apps. | 1285 // We do not allow absolute intent URLs in non-hosted apps. |
1186 if (GURL(value).is_valid()) { | 1286 if (GURL(value).is_valid()) { |
1187 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( | 1287 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( |
1188 errors::kCannotAccessPage,value.c_str()); | 1288 errors::kCannotAccessPage, value.c_str()); |
1189 return false; | 1289 return false; |
1190 } | 1290 } |
1191 service.service_url = GetResourceURL(value); | 1291 service.service_url = GetResourceURL(value); |
1192 } | 1292 } |
1193 } | 1293 } |
1194 | 1294 |
1195 if (one_service->HasKey(keys::kIntentTitle) && | 1295 if (one_service->HasKey(keys::kIntentTitle) && |
1196 !one_service->GetString(keys::kIntentTitle, &service.title)) { | 1296 !one_service->GetString(keys::kIntentTitle, &service.title)) { |
1197 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); | 1297 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); |
1198 return false; | 1298 return false; |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1712 minimum_version_string); | 1812 minimum_version_string); |
1713 return false; | 1813 return false; |
1714 } | 1814 } |
1715 } | 1815 } |
1716 | 1816 |
1717 // Initialize converted_from_user_script (if present) | 1817 // Initialize converted_from_user_script (if present) |
1718 if (manifest->HasKey(keys::kConvertedFromUserScript)) | 1818 if (manifest->HasKey(keys::kConvertedFromUserScript)) |
1719 manifest->GetBoolean(keys::kConvertedFromUserScript, | 1819 manifest->GetBoolean(keys::kConvertedFromUserScript, |
1720 &converted_from_user_script_); | 1820 &converted_from_user_script_); |
1721 | 1821 |
1822 // Initialize commands (if present). | |
1823 if (manifest->HasKey(keys::kCommands)) { | |
1824 DictionaryValue* commands = NULL; | |
1825 if (!manifest->GetDictionary(keys::kCommands, &commands)) { | |
1826 *error = ASCIIToUTF16(errors::kInvalidCommandsKey); | |
1827 return false; | |
1828 } | |
1829 | |
1830 int command_index = 0; | |
1831 for (DictionaryValue::key_iterator iter = commands->begin_keys(); | |
1832 iter != commands->end_keys(); ++iter) { | |
1833 ++command_index; | |
1834 | |
1835 DictionaryValue* command = NULL; | |
1836 if (!commands->GetDictionary(*iter, &command)) { | |
1837 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
1838 errors::kInvalidKeyBindingDictionary, | |
1839 base::IntToString(command_index)); | |
1840 return false; | |
1841 } | |
1842 | |
1843 ExtensionKeybinding binding; | |
1844 if (!binding.Parse(command, *iter, command_index, error)) | |
1845 return false; // |error| already set. | |
1846 | |
1847 commands_.push_back(binding); | |
1848 } | |
1849 } | |
1850 | |
1722 // Initialize icons (if present). | 1851 // Initialize icons (if present). |
1723 if (manifest->HasKey(keys::kIcons)) { | 1852 if (manifest->HasKey(keys::kIcons)) { |
1724 DictionaryValue* icons_value = NULL; | 1853 DictionaryValue* icons_value = NULL; |
1725 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { | 1854 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { |
1726 *error = ASCIIToUTF16(errors::kInvalidIcons); | 1855 *error = ASCIIToUTF16(errors::kInvalidIcons); |
1727 return false; | 1856 return false; |
1728 } | 1857 } |
1729 | 1858 |
1730 for (size_t i = 0; i < arraysize(kIconSizes); ++i) { | 1859 for (size_t i = 0; i < arraysize(kIconSizes); ++i) { |
1731 std::string key = base::IntToString(kIconSizes[i]); | 1860 std::string key = base::IntToString(kIconSizes[i]); |
(...skipping 1143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2875 | 3004 |
2876 if (permission->id() == ExtensionAPIPermission::kExperimental) { | 3005 if (permission->id() == ExtensionAPIPermission::kExperimental) { |
2877 if (!CanSpecifyExperimentalPermission()) { | 3006 if (!CanSpecifyExperimentalPermission()) { |
2878 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); | 3007 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); |
2879 return false; | 3008 return false; |
2880 } | 3009 } |
2881 } | 3010 } |
2882 | 3011 |
2883 bool supports_type = false; | 3012 bool supports_type = false; |
2884 switch (GetType()) { | 3013 switch (GetType()) { |
2885 case TYPE_USER_SCRIPT: // Pass through. | 3014 case TYPE_USER_SCRIPT: // Pass through. |
2886 case TYPE_EXTENSION: | 3015 case TYPE_EXTENSION: |
2887 supports_type = permission->supports_extensions(); | 3016 supports_type = permission->supports_extensions(); |
2888 break; | 3017 break; |
2889 case TYPE_HOSTED_APP: | 3018 case TYPE_HOSTED_APP: |
2890 supports_type = permission->supports_hosted_apps(); | 3019 supports_type = permission->supports_hosted_apps(); |
2891 break; | 3020 break; |
2892 case TYPE_PACKAGED_APP: | 3021 case TYPE_PACKAGED_APP: |
2893 supports_type = permission->supports_packaged_apps(); | 3022 supports_type = permission->supports_packaged_apps(); |
2894 break; | 3023 break; |
2895 case TYPE_PLATFORM_APP: | 3024 case TYPE_PLATFORM_APP: |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3031 } | 3160 } |
3032 } | 3161 } |
3033 | 3162 |
3034 bool Extension::IsSyncable() const { | 3163 bool Extension::IsSyncable() const { |
3035 // TODO(akalin): Figure out if we need to allow some other types. | 3164 // TODO(akalin): Figure out if we need to allow some other types. |
3036 | 3165 |
3037 // We want to sync any extensions that are shown in the luancher because | 3166 // We want to sync any extensions that are shown in the luancher because |
3038 // their positions should sync. | 3167 // their positions should sync. |
3039 return location_ == Extension::INTERNAL || | 3168 return location_ == Extension::INTERNAL || |
3040 ShouldDisplayInLauncher(); | 3169 ShouldDisplayInLauncher(); |
3041 | |
3042 } | 3170 } |
3043 | 3171 |
3044 bool Extension::ShouldDisplayInLauncher() const { | 3172 bool Extension::ShouldDisplayInLauncher() const { |
3045 // All apps should be displayed on the NTP except for the Cloud Print App. | 3173 // All apps should be displayed on the NTP except for the Cloud Print App. |
3046 return is_app() && id() != extension_misc::kCloudPrintAppId; | 3174 return is_app() && id() != extension_misc::kCloudPrintAppId; |
3047 } | 3175 } |
3048 | 3176 |
3049 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, | 3177 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, |
3050 const std::string& id, | 3178 const std::string& id, |
3051 const FilePath& path, | 3179 const FilePath& path, |
(...skipping 29 matching lines...) Expand all Loading... | |
3081 already_disabled(false), | 3209 already_disabled(false), |
3082 extension(extension) {} | 3210 extension(extension) {} |
3083 | 3211 |
3084 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3212 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
3085 const Extension* extension, | 3213 const Extension* extension, |
3086 const ExtensionPermissionSet* permissions, | 3214 const ExtensionPermissionSet* permissions, |
3087 Reason reason) | 3215 Reason reason) |
3088 : reason(reason), | 3216 : reason(reason), |
3089 extension(extension), | 3217 extension(extension), |
3090 permissions(permissions) {} | 3218 permissions(permissions) {} |
OLD | NEW |