OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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_file_util.h" | 5 #include "chrome/common/extensions/extension_file_util.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/scoped_temp_dir.h" | 13 #include "base/scoped_temp_dir.h" |
14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
15 #include "chrome/common/extensions/extension.h" | 15 #include "chrome/common/extensions/extension.h" |
16 #include "chrome/common/extensions/extension_l10n_util.h" | 16 #include "chrome/common/extensions/extension_l10n_util.h" |
17 #include "chrome/common/extensions/extension_constants.h" | 17 #include "chrome/common/extensions/extension_constants.h" |
18 #include "chrome/common/json_value_serializer.h" | 18 #include "chrome/common/json_value_serializer.h" |
| 19 #include "grit/generated_resources.h" |
19 #include "net/base/escape.h" | 20 #include "net/base/escape.h" |
20 #include "net/base/file_stream.h" | 21 #include "net/base/file_stream.h" |
21 | 22 |
22 namespace errors = extension_manifest_errors; | 23 namespace errors = extension_manifest_errors; |
23 namespace keys = extension_manifest_keys; | |
24 | 24 |
25 namespace extension_file_util { | 25 namespace extension_file_util { |
26 | 26 |
27 // Validates locale info. Doesn't check if messages.json files are valid. | 27 // Validates locale info. Doesn't check if messages.json files are valid. |
28 static bool ValidateLocaleInfo(const Extension& extension, std::string* error); | 28 static bool ValidateLocaleInfo(const Extension& extension, std::string* error); |
29 | 29 |
30 const char kInstallDirectoryName[] = "Extensions"; | 30 const char kInstallDirectoryName[] = "Extensions"; |
31 // TODO(mpcomplete): obsolete. remove after migration period. | 31 // TODO(mpcomplete): obsolete. remove after migration period. |
32 // http://code.google.com/p/chromium/issues/detail?id=19733 | 32 // http://code.google.com/p/chromium/issues/detail?id=19733 |
33 const char kCurrentVersionFileName[] = "Current Version"; | 33 const char kCurrentVersionFileName[] = "Current Version"; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 } | 89 } |
90 | 90 |
91 bool InstallExtension(const FilePath& src_dir, | 91 bool InstallExtension(const FilePath& src_dir, |
92 const FilePath& version_dir, | 92 const FilePath& version_dir, |
93 std::string* error) { | 93 std::string* error) { |
94 // If anything fails after this, we want to delete the extension dir. | 94 // If anything fails after this, we want to delete the extension dir. |
95 ScopedTempDir scoped_version_dir; | 95 ScopedTempDir scoped_version_dir; |
96 scoped_version_dir.Set(version_dir); | 96 scoped_version_dir.Set(version_dir); |
97 | 97 |
98 if (!MoveDirSafely(src_dir, version_dir)) { | 98 if (!MoveDirSafely(src_dir, version_dir)) { |
99 *error = "Could not move extension directory into profile."; | 99 *error = l10n_util::GetStringUTF8( |
| 100 IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED); |
100 return false; | 101 return false; |
101 } | 102 } |
102 | 103 |
103 scoped_version_dir.Take(); | 104 scoped_version_dir.Take(); |
104 return true; | 105 return true; |
105 } | 106 } |
106 | 107 |
107 Extension* LoadExtension(const FilePath& extension_path, | 108 Extension* LoadExtension(const FilePath& extension_path, |
108 bool require_key, | 109 bool require_key, |
109 std::string* error) { | 110 std::string* error) { |
110 FilePath manifest_path = | 111 FilePath manifest_path = |
111 extension_path.Append(Extension::kManifestFilename); | 112 extension_path.Append(Extension::kManifestFilename); |
112 if (!file_util::PathExists(manifest_path)) { | 113 if (!file_util::PathExists(manifest_path)) { |
113 *error = extension_manifest_errors::kManifestUnreadable; | 114 *error = |
| 115 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_UNREADABLE); |
114 return NULL; | 116 return NULL; |
115 } | 117 } |
116 | 118 |
117 JSONFileValueSerializer serializer(manifest_path); | 119 JSONFileValueSerializer serializer(manifest_path); |
118 scoped_ptr<Value> root(serializer.Deserialize(error)); | 120 scoped_ptr<Value> root(serializer.Deserialize(error)); |
119 if (!root.get()) { | 121 if (!root.get()) { |
120 if (error->empty()) { | 122 if (error->empty()) { |
121 // If |error| is empty, than the file could not be read. | 123 // If |error| is empty, than the file could not be read. |
122 // It would be cleaner to have the JSON reader give a specific error | 124 // It would be cleaner to have the JSON reader give a specific error |
123 // in this case, but other code tests for a file error with | 125 // in this case, but other code tests for a file error with |
124 // error->empty(). For now, be consistent. | 126 // error->empty(). For now, be consistent. |
125 *error = extension_manifest_errors::kManifestUnreadable; | 127 *error = |
| 128 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_UNREADABLE); |
126 } else { | 129 } else { |
127 *error = StringPrintf("%s %s", | 130 *error = StringPrintf("%s %s", |
128 extension_manifest_errors::kManifestParseError, | 131 errors::kManifestParseError, |
129 error->c_str()); | 132 error->c_str()); |
130 } | 133 } |
131 return NULL; | 134 return NULL; |
132 } | 135 } |
133 | 136 |
134 if (!root->IsType(Value::TYPE_DICTIONARY)) { | 137 if (!root->IsType(Value::TYPE_DICTIONARY)) { |
135 *error = extension_manifest_errors::kInvalidManifest; | 138 *error = |
| 139 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID); |
136 return NULL; | 140 return NULL; |
137 } | 141 } |
138 | 142 |
139 DictionaryValue* manifest = static_cast<DictionaryValue*>(root.get()); | 143 DictionaryValue* manifest = static_cast<DictionaryValue*>(root.get()); |
140 | 144 |
141 scoped_ptr<Extension> extension(new Extension(extension_path)); | 145 scoped_ptr<Extension> extension(new Extension(extension_path)); |
142 | 146 |
143 if (!extension_l10n_util::LocalizeExtension(extension.get(), manifest, error)) | 147 if (!extension_l10n_util::LocalizeExtension(extension.get(), manifest, error)) |
144 return NULL; | 148 return NULL; |
145 | 149 |
146 if (!extension->InitFromValue(*manifest, require_key, error)) | 150 if (!extension->InitFromValue(*manifest, require_key, error)) |
147 return NULL; | 151 return NULL; |
148 | 152 |
149 if (!ValidateExtension(extension.get(), error)) | 153 if (!ValidateExtension(extension.get(), error)) |
150 return NULL; | 154 return NULL; |
151 | 155 |
152 return extension.release(); | 156 return extension.release(); |
153 } | 157 } |
154 | 158 |
155 bool ValidateExtension(Extension* extension, std::string* error) { | 159 bool ValidateExtension(Extension* extension, std::string* error) { |
156 // Validate icons exist. | 160 // Validate icons exist. |
157 for (std::map<int, std::string>::const_iterator iter = | 161 for (std::map<int, std::string>::const_iterator iter = |
158 extension->icons().begin(); iter != extension->icons().end(); ++iter) { | 162 extension->icons().begin(); iter != extension->icons().end(); ++iter) { |
159 const FilePath path = extension->GetResource(iter->second).GetFilePath(); | 163 const FilePath path = extension->GetResource(iter->second).GetFilePath(); |
160 if (!file_util::PathExists(path)) { | 164 if (!file_util::PathExists(path)) { |
161 *error = StringPrintf("Could not load extension icon '%s'.", | 165 *error = |
162 iter->second.c_str()); | 166 l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_ICON_FAILED, |
| 167 UTF8ToUTF16(iter->second)); |
163 return false; | 168 return false; |
164 } | 169 } |
165 } | 170 } |
166 | 171 |
167 // Theme resource validation. | 172 // Theme resource validation. |
168 if (extension->IsTheme()) { | 173 if (extension->IsTheme()) { |
169 DictionaryValue* images_value = extension->GetThemeImages(); | 174 DictionaryValue* images_value = extension->GetThemeImages(); |
170 if (images_value) { | 175 if (images_value) { |
171 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); | 176 for (DictionaryValue::key_iterator iter = images_value->begin_keys(); |
172 iter != images_value->end_keys(); ++iter) { | 177 iter != images_value->end_keys(); ++iter) { |
173 std::string val; | 178 std::string val; |
174 if (images_value->GetStringWithoutPathExpansion(*iter, &val)) { | 179 if (images_value->GetStringWithoutPathExpansion(*iter, &val)) { |
175 FilePath image_path = extension->path().AppendASCII(val); | 180 FilePath image_path = extension->path().AppendASCII(val); |
176 if (!file_util::PathExists(image_path)) { | 181 if (!file_util::PathExists(image_path)) { |
177 *error = StringPrintf( | 182 *error = |
178 "Could not load '%s' for theme.", | 183 l10n_util::GetStringFUTF8(IDS_EXTENSION_INVALID_IMAGE_PATH, |
179 WideToUTF8(image_path.ToWStringHack()).c_str()); | 184 WideToUTF16(image_path.ToWStringHack())); |
180 return false; | 185 return false; |
181 } | 186 } |
182 } | 187 } |
183 } | 188 } |
184 } | 189 } |
185 | 190 |
186 // Themes cannot contain other extension types. | 191 // Themes cannot contain other extension types. |
187 return true; | 192 return true; |
188 } | 193 } |
189 | 194 |
190 // Validate that claimed script resources actually exist. | 195 // Validate that claimed script resources actually exist. |
191 for (size_t i = 0; i < extension->content_scripts().size(); ++i) { | 196 for (size_t i = 0; i < extension->content_scripts().size(); ++i) { |
192 const UserScript& script = extension->content_scripts()[i]; | 197 const UserScript& script = extension->content_scripts()[i]; |
193 | 198 |
194 for (size_t j = 0; j < script.js_scripts().size(); j++) { | 199 for (size_t j = 0; j < script.js_scripts().size(); j++) { |
195 const UserScript::File& js_script = script.js_scripts()[j]; | 200 const UserScript::File& js_script = script.js_scripts()[j]; |
196 const FilePath& path = ExtensionResource::GetFilePath( | 201 const FilePath& path = ExtensionResource::GetFilePath( |
197 js_script.extension_root(), js_script.relative_path()); | 202 js_script.extension_root(), js_script.relative_path()); |
198 if (!file_util::PathExists(path)) { | 203 if (!file_util::PathExists(path)) { |
199 *error = StringPrintf( | 204 *error = |
200 "Could not load javascript '%s' for content script.", | 205 l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_JAVASCRIPT_FAILED, |
201 WideToUTF8(js_script.relative_path().ToWStringHack()).c_str()); | 206 WideToUTF16(js_script.relative_path().ToWStringHack())); |
202 return false; | 207 return false; |
203 } | 208 } |
204 } | 209 } |
205 | 210 |
206 for (size_t j = 0; j < script.css_scripts().size(); j++) { | 211 for (size_t j = 0; j < script.css_scripts().size(); j++) { |
207 const UserScript::File& css_script = script.css_scripts()[j]; | 212 const UserScript::File& css_script = script.css_scripts()[j]; |
208 const FilePath& path = ExtensionResource::GetFilePath( | 213 const FilePath& path = ExtensionResource::GetFilePath( |
209 css_script.extension_root(), css_script.relative_path()); | 214 css_script.extension_root(), css_script.relative_path()); |
210 if (!file_util::PathExists(path)) { | 215 if (!file_util::PathExists(path)) { |
211 *error = StringPrintf( | 216 *error = |
212 "Could not load css '%s' for content script.", | 217 l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_CSS_FAILED, |
213 WideToUTF8(css_script.relative_path().ToWStringHack()).c_str()); | 218 WideToUTF16(css_script.relative_path().ToWStringHack())); |
214 return false; | 219 return false; |
215 } | 220 } |
216 } | 221 } |
217 } | 222 } |
218 | 223 |
219 // Validate claimed plugin paths. | 224 // Validate claimed plugin paths. |
220 for (size_t i = 0; i < extension->plugins().size(); ++i) { | 225 for (size_t i = 0; i < extension->plugins().size(); ++i) { |
221 const Extension::PluginInfo& plugin = extension->plugins()[i]; | 226 const Extension::PluginInfo& plugin = extension->plugins()[i]; |
222 if (!file_util::PathExists(plugin.path)) { | 227 if (!file_util::PathExists(plugin.path)) { |
223 *error = StringPrintf("Could not load '%s' for plugin.", | 228 *error = |
224 WideToUTF8(plugin.path.ToWStringHack()).c_str()); | 229 l10n_util::GetStringFUTF8( |
| 230 IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED, |
| 231 WideToUTF16(plugin.path.ToWStringHack())); |
225 return false; | 232 return false; |
226 } | 233 } |
227 } | 234 } |
228 | 235 |
229 // Validate icon location for page actions. | 236 // Validate icon location for page actions. |
230 ExtensionAction* page_action = extension->page_action(); | 237 ExtensionAction* page_action = extension->page_action(); |
231 if (page_action) { | 238 if (page_action) { |
232 std::vector<std::string> icon_paths(*page_action->icon_paths()); | 239 std::vector<std::string> icon_paths(*page_action->icon_paths()); |
233 if (!page_action->default_icon_path().empty()) | 240 if (!page_action->default_icon_path().empty()) |
234 icon_paths.push_back(page_action->default_icon_path()); | 241 icon_paths.push_back(page_action->default_icon_path()); |
235 for (std::vector<std::string>::iterator iter = icon_paths.begin(); | 242 for (std::vector<std::string>::iterator iter = icon_paths.begin(); |
236 iter != icon_paths.end(); ++iter) { | 243 iter != icon_paths.end(); ++iter) { |
237 if (!file_util::PathExists(extension->GetResource(*iter).GetFilePath())) { | 244 if (!file_util::PathExists(extension->GetResource(*iter).GetFilePath())) { |
238 *error = StringPrintf("Could not load icon '%s' for page action.", | 245 *error = |
239 iter->c_str()); | 246 l10n_util::GetStringFUTF8( |
| 247 IDS_EXTENSION_LOAD_ICON_FOR_PAGE_ACTION_FAILED, |
| 248 UTF8ToUTF16(*iter)); |
240 return false; | 249 return false; |
241 } | 250 } |
242 } | 251 } |
243 } | 252 } |
244 | 253 |
245 // Validate icon location for browser actions. | 254 // Validate icon location for browser actions. |
246 // Note: browser actions don't use the icon_paths(). | 255 // Note: browser actions don't use the icon_paths(). |
247 ExtensionAction* browser_action = extension->browser_action(); | 256 ExtensionAction* browser_action = extension->browser_action(); |
248 if (browser_action) { | 257 if (browser_action) { |
249 std::string path = browser_action->default_icon_path(); | 258 std::string path = browser_action->default_icon_path(); |
250 if (!path.empty() && | 259 if (!path.empty() && |
251 !file_util::PathExists(extension->GetResource(path).GetFilePath())) { | 260 !file_util::PathExists(extension->GetResource(path).GetFilePath())) { |
252 *error = StringPrintf("Could not load icon '%s' for browser action.", | 261 *error = |
253 path.c_str()); | 262 l10n_util::GetStringFUTF8( |
| 263 IDS_EXTENSION_LOAD_ICON_FOR_BROWSER_ACTION_FAILED, |
| 264 UTF8ToUTF16(path)); |
254 return false; | 265 return false; |
255 } | 266 } |
256 } | 267 } |
257 | 268 |
258 // Validate background page location. | 269 // Validate background page location. |
259 if (!extension->background_url().is_empty()) { | 270 if (!extension->background_url().is_empty()) { |
260 FilePath page_path = ExtensionURLToRelativeFilePath( | 271 FilePath page_path = ExtensionURLToRelativeFilePath( |
261 extension->background_url()); | 272 extension->background_url()); |
262 const FilePath path = extension->GetResource(page_path).GetFilePath(); | 273 const FilePath path = extension->GetResource(page_path).GetFilePath(); |
263 if (path.empty() || !file_util::PathExists(path)) { | 274 if (path.empty() || !file_util::PathExists(path)) { |
264 *error = StringPrintf("Could not load background page '%s'.", | 275 *error = |
265 WideToUTF8(page_path.ToWStringHack()).c_str()); | 276 l10n_util::GetStringFUTF8( |
| 277 IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED, |
| 278 WideToUTF16(page_path.ToWStringHack())); |
266 return false; | 279 return false; |
267 } | 280 } |
268 } | 281 } |
269 | 282 |
270 // Validate locale info. | 283 // Validate locale info. |
271 if (!ValidateLocaleInfo(*extension, error)) | 284 if (!ValidateLocaleInfo(*extension, error)) |
272 return false; | 285 return false; |
273 | 286 |
274 // Check children of extension root to see if any of them start with _ and is | 287 // Check children of extension root to see if any of them start with _ and is |
275 // not on the reserved list. | 288 // not on the reserved list. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 FilePath locale_path = extension_path.Append(Extension::kLocaleFolder); | 395 FilePath locale_path = extension_path.Append(Extension::kLocaleFolder); |
383 if (!file_util::PathExists(locale_path)) | 396 if (!file_util::PathExists(locale_path)) |
384 return NULL; | 397 return NULL; |
385 | 398 |
386 std::set<std::string> locales; | 399 std::set<std::string> locales; |
387 if (!extension_l10n_util::GetValidLocales(locale_path, &locales, error)) | 400 if (!extension_l10n_util::GetValidLocales(locale_path, &locales, error)) |
388 return NULL; | 401 return NULL; |
389 | 402 |
390 if (default_locale.empty() || | 403 if (default_locale.empty() || |
391 locales.find(default_locale) == locales.end()) { | 404 locales.find(default_locale) == locales.end()) { |
392 *error = extension_manifest_errors::kLocalesNoDefaultLocaleSpecified; | 405 *error = l10n_util::GetStringUTF8( |
| 406 IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED); |
393 return NULL; | 407 return NULL; |
394 } | 408 } |
395 | 409 |
396 ExtensionMessageBundle* message_bundle = | 410 ExtensionMessageBundle* message_bundle = |
397 extension_l10n_util::LoadMessageCatalogs( | 411 extension_l10n_util::LoadMessageCatalogs( |
398 locale_path, | 412 locale_path, |
399 default_locale, | 413 default_locale, |
400 extension_l10n_util::CurrentLocaleOrDefault(), | 414 extension_l10n_util::CurrentLocaleOrDefault(), |
401 locales, | 415 locales, |
402 error); | 416 error); |
403 | 417 |
404 return message_bundle; | 418 return message_bundle; |
405 } | 419 } |
406 | 420 |
407 static bool ValidateLocaleInfo(const Extension& extension, std::string* error) { | 421 static bool ValidateLocaleInfo(const Extension& extension, std::string* error) { |
408 // default_locale and _locales have to be both present or both missing. | 422 // default_locale and _locales have to be both present or both missing. |
409 const FilePath path = extension.path().Append(Extension::kLocaleFolder); | 423 const FilePath path = extension.path().Append(Extension::kLocaleFolder); |
410 bool path_exists = file_util::PathExists(path); | 424 bool path_exists = file_util::PathExists(path); |
411 std::string default_locale = extension.default_locale(); | 425 std::string default_locale = extension.default_locale(); |
412 | 426 |
413 // If both default locale and _locales folder are empty, skip verification. | 427 // If both default locale and _locales folder are empty, skip verification. |
414 if (default_locale.empty() && !path_exists) | 428 if (default_locale.empty() && !path_exists) |
415 return true; | 429 return true; |
416 | 430 |
417 if (default_locale.empty() && path_exists) { | 431 if (default_locale.empty() && path_exists) { |
418 *error = errors::kLocalesNoDefaultLocaleSpecified; | 432 *error = l10n_util::GetStringUTF8( |
| 433 IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED); |
419 return false; | 434 return false; |
420 } else if (!default_locale.empty() && !path_exists) { | 435 } else if (!default_locale.empty() && !path_exists) { |
421 *error = errors::kLocalesTreeMissing; | 436 *error = errors::kLocalesTreeMissing; |
422 return false; | 437 return false; |
423 } | 438 } |
424 | 439 |
425 // Treat all folders under _locales as valid locales. | 440 // Treat all folders under _locales as valid locales. |
426 file_util::FileEnumerator locales(path, | 441 file_util::FileEnumerator locales(path, |
427 false, | 442 false, |
428 file_util::FileEnumerator::DIRECTORIES); | 443 file_util::FileEnumerator::DIRECTORIES); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); | 524 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); |
510 | 525 |
511 #if defined(OS_POSIX) | 526 #if defined(OS_POSIX) |
512 return FilePath(file_path); | 527 return FilePath(file_path); |
513 #elif defined(OS_WIN) | 528 #elif defined(OS_WIN) |
514 return FilePath(UTF8ToWide(file_path)); | 529 return FilePath(UTF8ToWide(file_path)); |
515 #endif | 530 #endif |
516 } | 531 } |
517 | 532 |
518 } // namespace extension_file_util | 533 } // namespace extension_file_util |
OLD | NEW |