Chromium Code Reviews| 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" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 #include "chrome/common/extensions/file_browser_handler.h" | 35 #include "chrome/common/extensions/file_browser_handler.h" |
| 36 #include "chrome/common/extensions/manifest.h" | 36 #include "chrome/common/extensions/manifest.h" |
| 37 #include "chrome/common/extensions/user_script.h" | 37 #include "chrome/common/extensions/user_script.h" |
| 38 #include "chrome/common/url_constants.h" | 38 #include "chrome/common/url_constants.h" |
| 39 #include "googleurl/src/url_util.h" | 39 #include "googleurl/src/url_util.h" |
| 40 #include "grit/chromium_strings.h" | 40 #include "grit/chromium_strings.h" |
| 41 #include "grit/generated_resources.h" | 41 #include "grit/generated_resources.h" |
| 42 #include "grit/theme_resources.h" | 42 #include "grit/theme_resources.h" |
| 43 #include "net/base/registry_controlled_domain.h" | 43 #include "net/base/registry_controlled_domain.h" |
| 44 #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" | |
| 45 #include "ui/base/l10n/l10n_util.h" | 46 #include "ui/base/l10n/l10n_util.h" |
| 46 #include "ui/base/resource/resource_bundle.h" | 47 #include "ui/base/resource/resource_bundle.h" |
| 47 #include "webkit/glue/image_decoder.h" | 48 #include "webkit/glue/image_decoder.h" |
| 48 #include "webkit/glue/web_intent_service_data.h" | 49 #include "webkit/glue/web_intent_service_data.h" |
| 49 | 50 |
| 50 namespace keys = extension_manifest_keys; | 51 namespace keys = extension_manifest_keys; |
| 51 namespace values = extension_manifest_values; | 52 namespace values = extension_manifest_values; |
| 52 namespace errors = extension_manifest_errors; | 53 namespace errors = extension_manifest_errors; |
| 53 | 54 |
| 54 using extensions::csp_validator::ContentSecurityPolicyIsLegal; | 55 using extensions::csp_validator::ContentSecurityPolicyIsLegal; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 shortcut_alt(false), | 213 shortcut_alt(false), |
| 213 shortcut_ctrl(false), | 214 shortcut_ctrl(false), |
| 214 shortcut_shift(false) { | 215 shortcut_shift(false) { |
| 215 } | 216 } |
| 216 | 217 |
| 217 Extension::InputComponentInfo::~InputComponentInfo() {} | 218 Extension::InputComponentInfo::~InputComponentInfo() {} |
| 218 | 219 |
| 219 Extension::TtsVoice::TtsVoice() {} | 220 Extension::TtsVoice::TtsVoice() {} |
| 220 Extension::TtsVoice::~TtsVoice() {} | 221 Extension::TtsVoice::~TtsVoice() {} |
| 221 | 222 |
| 223 Extension::ExtensionKeybinding::ExtensionKeybinding() {} | |
| 224 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} | |
| 225 | |
| 226 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, | |
| 227 const std::string& event_name, | |
| 228 string16* error, | |
| 229 int index) { | |
|
Matt Perry
2012/02/21 23:13:39
outparams (error) should go last
| |
| 230 std::string key_binding; | |
| 231 if (!command->GetString(keys::kKey, &key_binding)) { | |
| 232 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 233 errors::kInvalidKeyBinding, | |
| 234 base::IntToString(index), | |
| 235 "Missing"); | |
| 236 return false; | |
| 237 } | |
| 238 | |
| 239 std::string original_keybinding = key_binding; | |
| 240 // Normalize '-' to '+'. | |
| 241 for (size_t pos = key_binding.find('-'); | |
| 242 pos != std::string::npos; | |
| 243 pos = key_binding.find('-')) { | |
| 244 key_binding.replace(pos, 1, "+"); | |
| 245 } | |
| 246 // Remove all spaces. | |
| 247 for (size_t pos = key_binding.find(' '); | |
| 248 pos != std::string::npos; | |
| 249 pos = key_binding.find(' ')) { | |
| 250 key_binding.replace(pos, 1, ""); | |
| 251 } | |
|
Matt Perry
2012/02/21 23:13:39
base::ReplaceSubstringsAfterOffset(&key_binding, 0
| |
| 252 // And finally, lower-case it. | |
| 253 key_binding = StringToLowerASCII(key_binding); | |
| 254 | |
| 255 // Now, parse it into an accelerator. | |
| 256 bool ctrl = false; | |
| 257 bool alt = false; | |
| 258 bool shift = false; | |
| 259 ui::KeyboardCode key = ui::VKEY_UNKNOWN; | |
| 260 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not | |
| 261 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: | |
| 262 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. | |
| 263 size_t position; | |
|
Matt Perry
2012/02/21 23:13:39
Should we support Shift+Alt+foo? If so, it might b
Finnur
2012/02/22 23:45:22
Good idea.
On 2012/02/21 23:13:39, Matt Perry wro
| |
| 264 if ((position = key_binding.find("ctrl+")) != std::string::npos) { | |
| 265 ctrl = true; | |
| 266 key_binding = key_binding.replace(position, 5, ""); | |
| 267 } else if ((position = key_binding.find("alt+")) != std::string::npos) { | |
| 268 alt = true; | |
| 269 key_binding = key_binding.replace(position, 4, ""); | |
| 270 } | |
| 271 if ((position = key_binding.find("shift+")) != std::string::npos) { | |
| 272 shift = true; | |
| 273 key_binding = key_binding.replace(position, 6, ""); | |
| 274 } | |
| 275 // We've stripped everything from the string but the letter. | |
| 276 if (key_binding.size() != 1) { | |
| 277 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 278 errors::kInvalidKeyBinding, | |
| 279 base::IntToString(index), | |
| 280 original_keybinding); | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 if (key_binding.compare("a") == 0) key = ui::VKEY_A; | |
|
Matt Perry
2012/02/21 23:13:39
Are we guaranteed for VKEY_A through _Z to be cont
| |
| 285 else if (key_binding.compare("b") == 0) key = ui::VKEY_B; | |
| 286 else if (key_binding.compare("c") == 0) key = ui::VKEY_C; | |
| 287 else if (key_binding.compare("d") == 0) key = ui::VKEY_D; | |
| 288 else if (key_binding.compare("e") == 0) key = ui::VKEY_E; | |
| 289 else if (key_binding.compare("f") == 0) key = ui::VKEY_F; | |
| 290 else if (key_binding.compare("g") == 0) key = ui::VKEY_G; | |
| 291 else if (key_binding.compare("h") == 0) key = ui::VKEY_H; | |
| 292 else if (key_binding.compare("i") == 0) key = ui::VKEY_I; | |
| 293 else if (key_binding.compare("j") == 0) key = ui::VKEY_J; | |
| 294 else if (key_binding.compare("k") == 0) key = ui::VKEY_K; | |
| 295 else if (key_binding.compare("l") == 0) key = ui::VKEY_L; | |
| 296 else if (key_binding.compare("m") == 0) key = ui::VKEY_M; | |
| 297 else if (key_binding.compare("n") == 0) key = ui::VKEY_N; | |
| 298 else if (key_binding.compare("o") == 0) key = ui::VKEY_O; | |
| 299 else if (key_binding.compare("p") == 0) key = ui::VKEY_P; | |
| 300 else if (key_binding.compare("q") == 0) key = ui::VKEY_Q; | |
| 301 else if (key_binding.compare("r") == 0) key = ui::VKEY_R; | |
| 302 else if (key_binding.compare("s") == 0) key = ui::VKEY_S; | |
| 303 else if (key_binding.compare("t") == 0) key = ui::VKEY_T; | |
| 304 else if (key_binding.compare("u") == 0) key = ui::VKEY_U; | |
| 305 else if (key_binding.compare("v") == 0) key = ui::VKEY_V; | |
| 306 else if (key_binding.compare("x") == 0) key = ui::VKEY_X; | |
| 307 else if (key_binding.compare("y") == 0) key = ui::VKEY_Y; | |
| 308 else if (key_binding.compare("z") == 0) key = ui::VKEY_Z; | |
| 309 | |
| 310 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); | |
| 311 if (!command->GetString(keys::kDescription, &description_)) { | |
| 312 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 313 errors::kInvalidKeyBindingDescription, | |
| 314 base::IntToString(index)); | |
| 315 return false; | |
| 316 } | |
| 317 | |
| 318 event_name_ = event_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, error, command_index)) | |
| 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 |