172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 28ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Use of this source code is governed by a BSD-style license that can be 38ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// found in the LICENSE file. 48ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 58ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_file_util.h" 68ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 78ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include <map> 88ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include <vector> 98ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/file_util.h" 118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/logging.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h" 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/metrics/histogram.h" 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/path_service.h" 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/threading/thread_restrictions.h" 168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/utf_string_conversions.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/chrome_paths.h" 188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension.h" 198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_action.h" 208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_l10n_util.h" 218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_constants.h" 228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_resource.h" 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/extensions/extension_sidebar_defaults.h" 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/json_value_serializer.h" 258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "grit/generated_resources.h" 268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "net/base/escape.h" 278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "net/base/file_stream.h" 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsennamespace errors = extension_manifest_errors; 318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsennamespace extension_file_util { 338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Validates locale info. Doesn't check if messages.json files are valid. 358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenstatic bool ValidateLocaleInfo(const Extension& extension, std::string* error); 368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Returns false and sets the error if script file can't be loaded, 388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// or if it's not UTF-8 encoded. 398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenstatic bool IsScriptValid(const FilePath& path, const FilePath& relative_path, 408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen int message_id, std::string* error); 418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenconst char kInstallDirectoryName[] = "Extensions"; 438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 448ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenFilePath InstallExtension(const FilePath& unpacked_source_dir, 458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const std::string& id, 468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const std::string& version, 478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath& all_extensions_dir) { 488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath extension_dir = all_extensions_dir.AppendASCII(id); 498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath version_dir; 508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Create the extension directory if it doesn't exist already. 528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(extension_dir)) { 538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::CreateDirectory(extension_dir)) 548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return FilePath(); 558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Try to find a free directory. There can be legitimate conflicts in the case 588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // of overinstallation of the same version. 598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const int kMaxAttempts = 100; 608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (int i = 0; i < kMaxAttempts; ++i) { 618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath candidate = extension_dir.AppendASCII( 62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::StringPrintf("%s_%u", version.c_str(), i)); 638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(candidate)) { 648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen version_dir = candidate; 658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen break; 668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (version_dir.empty()) { 708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen LOG(ERROR) << "Could not find a home for extension " << id << " with " 718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen << "version " << version << "."; 728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return FilePath(); 738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::Move(unpacked_source_dir, version_dir)) 768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return FilePath(); 778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return version_dir; 798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvoid UninstallExtension(const FilePath& extensions_dir, 828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const std::string& id) { 838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // We don't care about the return value. If this fails (and it can, due to 848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // plugins that aren't unloaded yet, it will get cleaned up by 8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // ExtensionService::GarbageCollectExtensions). 868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::Delete(extensions_dir.AppendASCII(id), true); // recursive. 878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 89513209b27ff55e2841eac0e4120199c23acce758Ben Murdochscoped_refptr<Extension> LoadExtension(const FilePath& extension_path, 90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch Extension::Location location, 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int flags, 92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string* error) { 938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath manifest_path = 948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_path.Append(Extension::kManifestFilename); 958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(manifest_path)) { 96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *error = l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_UNREADABLE); 978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JSONFileValueSerializer serializer(manifest_path); 1018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen scoped_ptr<Value> root(serializer.Deserialize(NULL, error)); 1028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!root.get()) { 1038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (error->empty()) { 1048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If |error| is empty, than the file could not be read. 1058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // It would be cleaner to have the JSON reader give a specific error 1068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // in this case, but other code tests for a file error with 1078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // error->empty(). For now, be consistent. 108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *error = l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_UNREADABLE); 1098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 110513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *error = base::StringPrintf("%s %s", 111513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch errors::kManifestParseError, 112513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch error->c_str()); 1138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 1158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!root->IsType(Value::TYPE_DICTIONARY)) { 118513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *error = l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID); 1198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 1208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen DictionaryValue* manifest = static_cast<DictionaryValue*>(root.get()); 123513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!extension_l10n_util::LocalizeExtension(extension_path, manifest, error)) 1248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 1258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 126513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch scoped_refptr<Extension> extension(Extension::Create( 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen extension_path, 128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen location, 129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen *manifest, 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen flags, 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen error)); 132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!extension.get()) 1338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 1348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!ValidateExtension(extension.get(), error)) 1368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 1378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return extension; 1398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ValidateExtension(Extension* extension, std::string* error) { 1428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate icons exist. 1438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (ExtensionIconSet::IconMap::const_iterator iter = 1448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension->icons().map().begin(); 1458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen iter != extension->icons().map().end(); 1468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ++iter) { 1478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath path = extension->GetResource(iter->second).GetFilePath(); 1488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(path)) { 1498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 1508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_ICON_FAILED, 1518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen UTF8ToUTF16(iter->second)); 1528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 1538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Theme resource validation. 1578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (extension->is_theme()) { 1588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen DictionaryValue* images_value = extension->GetThemeImages(); 1598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (images_value) { 1608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (DictionaryValue::key_iterator iter = images_value->begin_keys(); 1618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen iter != images_value->end_keys(); ++iter) { 1628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string val; 1638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (images_value->GetStringWithoutPathExpansion(*iter, &val)) { 1648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath image_path = extension->path().AppendASCII(val); 1658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(image_path)) { 1668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 1678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8(IDS_EXTENSION_INVALID_IMAGE_PATH, 16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen image_path.LossyDisplayName()); 1698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 1708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Themes cannot contain other extension types. 1768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return true; 1778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate that claimed script resources actually exist, 1808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // and are UTF-8 encoded. 1818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (size_t i = 0; i < extension->content_scripts().size(); ++i) { 1828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const UserScript& script = extension->content_scripts()[i]; 1838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (size_t j = 0; j < script.js_scripts().size(); j++) { 1858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const UserScript::File& js_script = script.js_scripts()[j]; 1868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath& path = ExtensionResource::GetFilePath( 1878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen js_script.extension_root(), js_script.relative_path()); 1888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!IsScriptValid(path, js_script.relative_path(), 1898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_JAVASCRIPT_FAILED, error)) 1908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 1918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (size_t j = 0; j < script.css_scripts().size(); j++) { 1948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const UserScript::File& css_script = script.css_scripts()[j]; 1958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath& path = ExtensionResource::GetFilePath( 1968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen css_script.extension_root(), css_script.relative_path()); 1978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!IsScriptValid(path, css_script.relative_path(), 1988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_CSS_FAILED, error)) 1998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate claimed plugin paths. 2048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (size_t i = 0; i < extension->plugins().size(); ++i) { 2058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const Extension::PluginInfo& plugin = extension->plugins()[i]; 2068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(plugin.path)) { 2078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 2088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8( 2098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED, 21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen plugin.path.LossyDisplayName()); 2118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate icon location for page actions. 2168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ExtensionAction* page_action = extension->page_action(); 2178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (page_action) { 2188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::vector<std::string> icon_paths(*page_action->icon_paths()); 2198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!page_action->default_icon_path().empty()) 2208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen icon_paths.push_back(page_action->default_icon_path()); 2218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (std::vector<std::string>::iterator iter = icon_paths.begin(); 2228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen iter != icon_paths.end(); ++iter) { 2238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(extension->GetResource(*iter).GetFilePath())) { 2248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 2258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8( 2268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_ICON_FOR_PAGE_ACTION_FAILED, 2278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen UTF8ToUTF16(*iter)); 2288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate icon location for browser actions. 2348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Note: browser actions don't use the icon_paths(). 2358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ExtensionAction* browser_action = extension->browser_action(); 2368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (browser_action) { 2378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string path = browser_action->default_icon_path(); 2388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!path.empty() && 2398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen !file_util::PathExists(extension->GetResource(path).GetFilePath())) { 2408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 2418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8( 2428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_ICON_FOR_BROWSER_ACTION_FAILED, 2438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen UTF8ToUTF16(path)); 2448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Validate background page location, except for hosted apps, which should use 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // an external URL. Background page for hosted apps are verified when the 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // extension is created (in Extension::InitFromValue) 251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!extension->background_url().is_empty() && !extension->is_hosted_app()) { 2528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath page_path = ExtensionURLToRelativeFilePath( 2538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension->background_url()); 2548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath path = extension->GetResource(page_path).GetFilePath(); 2558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (path.empty() || !file_util::PathExists(path)) { 2568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 2578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8( 2588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED, 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen page_path.LossyDisplayName()); 2608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate path to the options page. Don't check the URL for hosted apps, 2658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // because they are expected to refer to an external URL. 2668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!extension->options_url().is_empty() && !extension->is_hosted_app()) { 2678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath options_path = ExtensionURLToRelativeFilePath( 2688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension->options_url()); 2698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath path = extension->GetResource(options_path).GetFilePath(); 2708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (path.empty() || !file_util::PathExists(path)) { 2718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = 2728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen l10n_util::GetStringFUTF8( 2738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED, 27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen options_path.LossyDisplayName()); 27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 27672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 27772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 27972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Validate sidebar default page location. 28072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionSidebarDefaults* sidebar_defaults = extension->sidebar_defaults(); 28172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (sidebar_defaults && sidebar_defaults->default_page().is_valid()) { 28272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath page_path = ExtensionURLToRelativeFilePath( 28372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen sidebar_defaults->default_page()); 28472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const FilePath path = extension->GetResource(page_path).GetFilePath(); 28572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (path.empty() || !file_util::PathExists(path)) { 28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *error = 28772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen l10n_util::GetStringFUTF8( 28872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IDS_EXTENSION_LOAD_SIDEBAR_PAGE_FAILED, 28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen page_path.LossyDisplayName()); 2908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Validate locale info. 2958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!ValidateLocaleInfo(*extension, error)) 2968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 2978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Check children of extension root to see if any of them start with _ and is 2998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // not on the reserved list. 3008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!CheckForIllegalFilenames(extension->path(), error)) { 3018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 3028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return true; 3058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvoid GarbageCollectExtensions( 3088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath& install_directory, 3098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const std::map<std::string, FilePath>& extension_paths) { 3108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Nothing to clean up if it doesn't exist. 3118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::DirectoryExists(install_directory)) 3128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return; 3138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Garbage collecting extensions..."; 3158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator enumerator(install_directory, 3168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen false, // Not recursive. 3178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator::DIRECTORIES); 3188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath extension_path; 3198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (extension_path = enumerator.Next(); !extension_path.value().empty(); 3208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_path = enumerator.Next()) { 32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string extension_id; 32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 32372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath basename = extension_path.BaseName(); 32472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (IsStringASCII(basename.value())) { 32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen extension_id = UTF16ToASCII(basename.LossyDisplayName()); 32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!Extension::IdIsValid(extension_id)) 32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen extension_id.clear(); 32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 3298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Delete directories that aren't valid IDs. 33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (extension_id.empty()) { 3328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen LOG(WARNING) << "Invalid extension ID encountered in extensions " 33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "directory: " << basename.value(); 334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Deleting invalid extension directory " 33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << extension_path.value() << "."; 3368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::Delete(extension_path, true); // Recursive. 3378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen continue; 3388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::map<std::string, FilePath>::const_iterator iter = 3418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_paths.find(extension_id); 3428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If there is no entry in the prefs file, just delete the directory and 3448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // move on. This can legitimately happen when an uninstall does not 3458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // complete, for example, when a plugin is in use at uninstall time. 3468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (iter == extension_paths.end()) { 347731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Deleting unreferenced install for directory " 34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << extension_path.LossyDisplayName() << "."; 3498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::Delete(extension_path, true); // Recursive. 3508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen continue; 3518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Clean up old version directories. 3548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator versions_enumerator( 3558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_path, 3568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen false, // Not recursive. 3578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator::DIRECTORIES); 3588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (FilePath version_dir = versions_enumerator.Next(); 3598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen !version_dir.value().empty(); 3608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen version_dir = versions_enumerator.Next()) { 3618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (version_dir.BaseName() != iter->second.BaseName()) { 362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Deleting old version for directory " 36372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << version_dir.LossyDisplayName() << "."; 3648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::Delete(version_dir, true); // Recursive. 3658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3708ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenExtensionMessageBundle* LoadExtensionMessageBundle( 3718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath& extension_path, 3728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const std::string& default_locale, 3738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string* error) { 3748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen error->clear(); 3758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Load locale information if available. 3768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath locale_path = extension_path.Append(Extension::kLocaleFolder); 3778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(locale_path)) 3788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 3798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::set<std::string> locales; 3818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!extension_l10n_util::GetValidLocales(locale_path, &locales, error)) 3828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 3838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (default_locale.empty() || 3858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen locales.find(default_locale) == locales.end()) { 3868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = l10n_util::GetStringUTF8( 3878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED); 3888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return NULL; 3898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ExtensionMessageBundle* message_bundle = 3928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_l10n_util::LoadMessageCatalogs( 3938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen locale_path, 3948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen default_locale, 3958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_l10n_util::CurrentLocaleOrDefault(), 3968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen locales, 3978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen error); 3988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return message_bundle; 4008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenstatic bool ValidateLocaleInfo(const Extension& extension, std::string* error) { 4038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // default_locale and _locales have to be both present or both missing. 4048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath path = extension.path().Append(Extension::kLocaleFolder); 4058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen bool path_exists = file_util::PathExists(path); 4068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string default_locale = extension.default_locale(); 4078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If both default locale and _locales folder are empty, skip verification. 4098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (default_locale.empty() && !path_exists) 4108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return true; 4118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (default_locale.empty() && path_exists) { 4138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = l10n_util::GetStringUTF8( 4148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED); 4158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 4168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else if (!default_locale.empty() && !path_exists) { 4178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = errors::kLocalesTreeMissing; 4188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 4198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Treat all folders under _locales as valid locales. 4228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator locales(path, 4238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen false, 4248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator::DIRECTORIES); 4258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::set<std::string> all_locales; 4278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_l10n_util::GetAllLocales(&all_locales); 4288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath default_locale_path = path.AppendASCII(default_locale); 4298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen bool has_default_locale_message_file = false; 4308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath locale_path; 4328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen while (!(locale_path = locales.Next()).empty()) { 4338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (extension_l10n_util::ShouldSkipValidation(path, locale_path, 4348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen all_locales)) 4358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen continue; 4368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath messages_path = 4388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen locale_path.Append(Extension::kMessagesFilename); 4398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(messages_path)) { 441513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *error = base::StringPrintf( 4428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "%s %s", errors::kLocalesMessagesFileMissing, 44372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF16ToUTF8(messages_path.LossyDisplayName()).c_str()); 4448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 4458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (locale_path == default_locale_path) 4488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen has_default_locale_message_file = true; 4498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Only message file for default locale has to exist. 4528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!has_default_locale_message_file) { 4538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = errors::kLocalesNoDefaultMessages; 4548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 4558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return true; 4588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenstatic bool IsScriptValid(const FilePath& path, 4618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen const FilePath& relative_path, 4628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen int message_id, 4638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string* error) { 4648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string content; 4658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!file_util::PathExists(path) || 4668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen !file_util::ReadFileToString(path, &content)) { 4678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = l10n_util::GetStringFUTF8( 4688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen message_id, 46972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen relative_path.LossyDisplayName()); 4708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 4718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!IsStringUTF8(content)) { 4748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *error = l10n_util::GetStringFUTF8( 4758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen IDS_EXTENSION_BAD_FILE_ENCODING, 47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen relative_path.LossyDisplayName()); 4778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 4788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return true; 4818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool CheckForIllegalFilenames(const FilePath& extension_path, 4848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string* error) { 4858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Reserved underscore names. 4868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen static const FilePath::CharType* reserved_names[] = { 4878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen Extension::kLocaleFolder, 4888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FILE_PATH_LITERAL("__MACOSX"), 4898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }; 4908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen static std::set<FilePath::StringType> reserved_underscore_names( 4918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen reserved_names, reserved_names + arraysize(reserved_names)); 4928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Enumerate all files and directories in the extension root. 4948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // There is a problem when using pattern "_*" with FileEnumerator, so we have 4958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // to cheat with find_first_of and match all. 4968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator all_files( 4978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen extension_path, 4988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen false, 4998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen static_cast<file_util::FileEnumerator::FILE_TYPE>( 5008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator::DIRECTORIES | 5018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_util::FileEnumerator::FILES)); 5028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath file; 5048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen while (!(file = all_files.Next()).empty()) { 5058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath::StringType filename = file.BaseName().value(); 5068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Skip all that don't start with "_". 5078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (filename.find_first_of(FILE_PATH_LITERAL("_")) != 0) continue; 5088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (reserved_underscore_names.find(filename) == 5098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen reserved_underscore_names.end()) { 510513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *error = base::StringPrintf( 511513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch "Cannot load extension with file or directory name %s. " 512513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch "Filenames starting with \"_\" are reserved for use by the system.", 513513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch filename.c_str()); 5148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return false; 5158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return true; 5198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 5208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5218ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenFilePath ExtensionURLToRelativeFilePath(const GURL& url) { 5228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string url_path = url.path(); 5238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (url_path.empty() || url_path[0] != '/') 5248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return FilePath(); 5258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Drop the leading slashes and convert %-encoded UTF8 to regular UTF8. 5278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen std::string file_path = UnescapeURLComponent(url_path, 5288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); 5298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen size_t skip = file_path.find_first_not_of("/\\"); 5308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (skip != file_path.npos) 5318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen file_path = file_path.substr(skip); 5328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath path = 5348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#if defined(OS_POSIX) 5358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath(file_path); 5368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#elif defined(OS_WIN) 5378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath(UTF8ToWide(file_path)); 5388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#else 5398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen FilePath(); 5408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen NOTIMPLEMENTED(); 5418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#endif 5428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // It's still possible for someone to construct an annoying URL whose path 5448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // would still wind up not being considered relative at this point. 5458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // For example: chrome-extension://id/c:////foo.html 5468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (path.IsAbsolute()) 5478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return FilePath(); 5488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return path; 5508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 5518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 55272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenFilePath GetUserDataTempDir() { 55372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We do file IO in this function, but only when the current profile's 55472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Temp directory has never been used before, or in a rare error case. 55572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Developers are not likely to see these situations often, so do an 55672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // explicit thread check. 55772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::ThreadRestrictions::AssertIOAllowed(); 55872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 55972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Getting chrome::DIR_USER_DATA_TEMP is failing. Use histogram to see why. 56072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(skerner): Fix the problem, and remove this code. crbug.com/70056 56172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen enum DirectoryCreationResult { 56272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SUCCESS = 0, 56372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 56472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CANT_GET_PARENT_PATH, 56572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CANT_GET_UDT_PATH, 56672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOT_A_DIRECTORY, 56772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CANT_CREATE_DIR, 56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CANT_WRITE_TO_PATH, 56972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 57072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UNSET, 57172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NUM_DIRECTORY_CREATION_RESULTS 57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen }; 57372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 57472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // All paths should set |result|. 57572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DirectoryCreationResult result = UNSET; 57672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 57772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath temp_path; 57872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!PathService::Get(chrome::DIR_USER_DATA_TEMP, &temp_path)) { 57972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath parent_path; 58072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!PathService::Get(chrome::DIR_USER_DATA, &parent_path)) 58172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = CANT_GET_PARENT_PATH; 58272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen else 58372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = CANT_GET_UDT_PATH; 58472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 58572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (file_util::PathExists(temp_path)) { 58672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 58772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Path exists. Check that it is a directory we can write to. 58872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!file_util::DirectoryExists(temp_path)) { 58972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = NOT_A_DIRECTORY; 59072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 59172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (!file_util::PathIsWritable(temp_path)) { 59272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = CANT_WRITE_TO_PATH; 59372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 59472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 59572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Temp is a writable directory. 59672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = SUCCESS; 59772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 59872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 59972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (!file_util::CreateDirectory(temp_path)) { 60072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Path doesn't exist, and we failed to create it. 60172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = CANT_CREATE_DIR; 60272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 60372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 60472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Successfully created the Temp directory. 60572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result = SUCCESS; 60672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 60772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 60872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UMA_HISTOGRAM_ENUMERATION("Extensions.GetUserDataTempDir", 60972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result, 61072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NUM_DIRECTORY_CREATION_RESULTS); 61172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 61272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (result == SUCCESS) 61372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return temp_path; 61472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 61572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return FilePath(); 61672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 61772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 618dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid DeleteFile(const FilePath& path, bool recursive) { 619dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen file_util::Delete(path, recursive); 620dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 621dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 6228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} // namespace extension_file_util 623