1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/file_util.h" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include <map> 8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <set> 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <string> 10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <utility> 11a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include <vector> 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 13a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/files/file_enumerator.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/files/file_path.h" 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/files/scoped_temp_dir.h" 17a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/json/json_file_value_serializer.h" 18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/logging.h" 19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/memory/scoped_ptr.h" 20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/strings/stringprintf.h" 21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/strings/utf_string_conversions.h" 22a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/threading/thread_restrictions.h" 23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/constants.h" 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension.h" 25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension_icon_set.h" 26c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension_l10n_util.h" 27a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/install_warning.h" 28a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/manifest.h" 29a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/manifest_constants.h" 30a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/manifest_handler.h" 31a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h" 32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/message_bundle.h" 330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "grit/extensions_strings.h" 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "net/base/escape.h" 35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/base/l10n/l10n_util.h" 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "url/gurl.h" 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace extensions { 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace file_util { 40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace { 41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Returns true if the given file path exists and is not zero-length. 43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool ValidateFilePath(const base::FilePath& path) { 44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int64 size = 0; 45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!base::PathExists(path) || 46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch !base::GetFileSize(path, &size) || 47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch size == 0) { 48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return false; 49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return true; 52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} // namespace 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 56a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst base::FilePath::CharType kTempDirectoryName[] = FILE_PATH_LITERAL("Temp"); 57a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 58a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbase::FilePath InstallExtension(const base::FilePath& unpacked_source_dir, 59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const std::string& id, 60a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const std::string& version, 61a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const base::FilePath& extensions_dir) { 62a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath extension_dir = extensions_dir.AppendASCII(id); 63a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath version_dir; 64a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 65a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Create the extension directory if it doesn't exist already. 66a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::PathExists(extension_dir)) { 67a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::CreateDirectory(extension_dir)) 68a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 69a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 70a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 71a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Get a temp directory on the same file system as the profile. 72a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath install_temp_dir = GetInstallTempDir(extensions_dir); 73a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::ScopedTempDir extension_temp_dir; 74a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (install_temp_dir.empty() || 75a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch !extension_temp_dir.CreateUniqueTempDirUnderPath(install_temp_dir)) { 76a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch LOG(ERROR) << "Creating of temp dir under in the profile failed."; 77a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 78a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 79a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath crx_temp_source = 80a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch extension_temp_dir.path().Append(unpacked_source_dir.BaseName()); 81a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::Move(unpacked_source_dir, crx_temp_source)) { 82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch LOG(ERROR) << "Moving extension from : " << unpacked_source_dir.value() 83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch << " to : " << crx_temp_source.value() << " failed."; 84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 86a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Try to find a free directory. There can be legitimate conflicts in the case 88a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // of overinstallation of the same version. 89a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const int kMaxAttempts = 100; 90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch for (int i = 0; i < kMaxAttempts; ++i) { 91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath candidate = extension_dir.AppendASCII( 92a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::StringPrintf("%s_%u", version.c_str(), i)); 93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::PathExists(candidate)) { 94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch version_dir = candidate; 95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch break; 96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (version_dir.empty()) { 100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch LOG(ERROR) << "Could not find a home for extension " << id << " with " 101a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch << "version " << version << "."; 102a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 103a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 105a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::Move(crx_temp_source, version_dir)) { 106a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch LOG(ERROR) << "Installing extension from : " << crx_temp_source.value() 107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch << " into : " << version_dir.value() << " failed."; 108a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 109a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 110a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 111a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return version_dir; 112a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 113a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 114a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid UninstallExtension(const base::FilePath& extensions_dir, 115a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const std::string& id) { 116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // We don't care about the return value. If this fails (and it can, due to 117a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // plugins that aren't unloaded yet), it will get cleaned up by 118a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // ExtensionGarbageCollector::GarbageCollectExtensions. 119a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::DeleteFile(extensions_dir.AppendASCII(id), true); // recursive. 120a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 121a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 122a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochscoped_refptr<Extension> LoadExtension(const base::FilePath& extension_path, 123a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch Manifest::Location location, 124a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch int flags, 125a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string* error) { 126a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return LoadExtension(extension_path, std::string(), location, flags, error); 127a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 128a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 129a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochscoped_refptr<Extension> LoadExtension(const base::FilePath& extension_path, 130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const std::string& extension_id, 131a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch Manifest::Location location, 132a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch int flags, 133a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string* error) { 134a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch scoped_ptr<base::DictionaryValue> manifest( 135a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch LoadManifest(extension_path, error)); 136a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!manifest.get()) 137a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 138a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!extension_l10n_util::LocalizeExtension( 139a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch extension_path, manifest.get(), error)) { 140a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 141a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 142a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 143a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch scoped_refptr<Extension> extension(Extension::Create( 144a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch extension_path, location, *manifest, flags, extension_id, error)); 145a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!extension.get()) 146a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 147a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 148a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::vector<InstallWarning> warnings; 149a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!ValidateExtension(extension.get(), error, &warnings)) 150a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 151a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch extension->AddInstallWarnings(warnings); 152a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 153a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return extension; 154a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 155a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 156a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbase::DictionaryValue* LoadManifest(const base::FilePath& extension_path, 157a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string* error) { 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return LoadManifest(extension_path, kManifestFilename, error); 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::DictionaryValue* LoadManifest( 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::FilePath& extension_path, 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::FilePath::CharType* manifest_filename, 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string* error) { 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::FilePath manifest_path = extension_path.Append(manifest_filename); 166a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::PathExists(manifest_path)) { 167a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch *error = l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_UNREADABLE); 168a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 169a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 170a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 171a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch JSONFileValueSerializer serializer(manifest_path); 172a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch scoped_ptr<base::Value> root(serializer.Deserialize(NULL, error)); 173a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!root.get()) { 174a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (error->empty()) { 175a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // If |error| is empty, than the file could not be read. 176a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // It would be cleaner to have the JSON reader give a specific error 177a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // in this case, but other code tests for a file error with 178a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // error->empty(). For now, be consistent. 179a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch *error = l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_UNREADABLE); 180a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } else { 181a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch *error = base::StringPrintf( 182a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch "%s %s", manifest_errors::kManifestParseError, error->c_str()); 183a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 184a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 185a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 186a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 187a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!root->IsType(base::Value::TYPE_DICTIONARY)) { 188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch *error = l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID); 189a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return NULL; 190a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 191a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 192a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return static_cast<base::DictionaryValue*>(root.release()); 193a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 194a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ValidateExtension(const Extension* extension, 196a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string* error, 197a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::vector<InstallWarning>* warnings) { 198a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Ask registered manifest handlers to validate their paths. 199a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!ManifestHandler::ValidateExtension(extension, error, warnings)) 200a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return false; 201a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 202a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Check children of extension root to see if any of them start with _ and is 203a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // not on the reserved list. We only warn, and do not block the loading of the 204a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // extension. 205a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string warning; 206a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!CheckForIllegalFilenames(extension->path(), &warning)) 207a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch warnings->push_back(InstallWarning(warning)); 208a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 209a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Check that extensions don't include private key files. 210a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::vector<base::FilePath> private_keys = 211a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch FindPrivateKeyFiles(extension->path()); 212a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (extension->creation_flags() & Extension::ERROR_ON_PRIVATE_KEY) { 213a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!private_keys.empty()) { 214a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Only print one of the private keys because l10n_util doesn't have a way 215a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // to translate a list of strings. 216a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch *error = 217a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch l10n_util::GetStringFUTF8(IDS_EXTENSION_CONTAINS_PRIVATE_KEY, 218a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch private_keys.front().LossyDisplayName()); 219a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return false; 220a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 221a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } else { 222a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch for (size_t i = 0; i < private_keys.size(); ++i) { 223a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch warnings->push_back(InstallWarning( 224a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch l10n_util::GetStringFUTF8(IDS_EXTENSION_CONTAINS_PRIVATE_KEY, 225a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch private_keys[i].LossyDisplayName()))); 226a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 227a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Only warn; don't block loading the extension. 228a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 229a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return true; 230a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 231a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 232a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstd::vector<base::FilePath> FindPrivateKeyFiles( 233a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const base::FilePath& extension_dir) { 234a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::vector<base::FilePath> result; 235a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Pattern matching only works at the root level, so filter manually. 236a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FileEnumerator traversal( 237a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch extension_dir, /*recursive=*/true, base::FileEnumerator::FILES); 238a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch for (base::FilePath current = traversal.Next(); !current.empty(); 239a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch current = traversal.Next()) { 240a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!current.MatchesExtension(kExtensionKeyFileExtension)) 241a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch continue; 242a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 243a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string key_contents; 244a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::ReadFileToString(current, &key_contents)) { 245a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // If we can't read the file, assume it's not a private key. 246a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch continue; 247a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 248a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string key_bytes; 249a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!Extension::ParsePEMKeyBytes(key_contents, &key_bytes)) { 250a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // If we can't parse the key, assume it's ok too. 251a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch continue; 252a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 253a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 254a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch result.push_back(current); 255a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 256a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return result; 257a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 258a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 259a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool CheckForIllegalFilenames(const base::FilePath& extension_path, 260a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string* error) { 261a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Reserved underscore names. 262a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch static const base::FilePath::CharType* reserved_names[] = { 263a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch kLocaleFolder, kPlatformSpecificFolder, FILE_PATH_LITERAL("__MACOSX"), }; 264a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch CR_DEFINE_STATIC_LOCAL( 265a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::set<base::FilePath::StringType>, 266a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch reserved_underscore_names, 267a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch (reserved_names, reserved_names + arraysize(reserved_names))); 268a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 269a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Enumerate all files and directories in the extension root. 270a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // There is a problem when using pattern "_*" with FileEnumerator, so we have 271a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // to cheat with find_first_of and match all. 272a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const int kFilesAndDirectories = 273a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES; 274a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FileEnumerator all_files(extension_path, false, kFilesAndDirectories); 275a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 276a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath file; 277a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch while (!(file = all_files.Next()).empty()) { 278a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath::StringType filename = file.BaseName().value(); 279a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Skip all that don't start with "_". 280a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (filename.find_first_of(FILE_PATH_LITERAL("_")) != 0) 281a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch continue; 282a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (reserved_underscore_names.find(filename) == 283a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch reserved_underscore_names.end()) { 284a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch *error = base::StringPrintf( 285a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch "Cannot load extension with file or directory name %s. " 286a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch "Filenames starting with \"_\" are reserved for use by the system.", 287a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch file.BaseName().AsUTF8Unsafe().c_str()); 288a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return false; 289a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 290a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 291a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 292a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return true; 293a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 294a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 295a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbase::FilePath GetInstallTempDir(const base::FilePath& extensions_dir) { 296a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // We do file IO in this function, but only when the current profile's 297a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Temp directory has never been used before, or in a rare error case. 298a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Developers are not likely to see these situations often, so do an 299a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // explicit thread check. 300a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::ThreadRestrictions::AssertIOAllowed(); 301a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 302a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Create the temp directory as a sub-directory of the Extensions directory. 303a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // This guarantees it is on the same file system as the extension's eventual 304a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // install target. 305a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::FilePath temp_path = extensions_dir.Append(kTempDirectoryName); 306a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (base::PathExists(temp_path)) { 307a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::DirectoryExists(temp_path)) { 308a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DLOG(WARNING) << "Not a directory: " << temp_path.value(); 309a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 310a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 311a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::PathIsWritable(temp_path)) { 312a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DLOG(WARNING) << "Can't write to path: " << temp_path.value(); 313a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 314a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 315a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // This is a directory we can write to. 316a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return temp_path; 317a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 318a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 319a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Directory doesn't exist, so create it. 320a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!base::CreateDirectory(temp_path)) { 321a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DLOG(WARNING) << "Couldn't create directory: " << temp_path.value(); 322a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return base::FilePath(); 323a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 324a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return temp_path; 325a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 326a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 327a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid DeleteFile(const base::FilePath& path, bool recursive) { 328a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::DeleteFile(path, recursive); 329a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 330a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)base::FilePath ExtensionURLToRelativeFilePath(const GURL& url) { 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string url_path = url.path(); 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (url_path.empty() || url_path[0] != '/') 334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::FilePath(); 335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Drop the leading slashes and convert %-encoded UTF8 to regular UTF8. 337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string file_path = net::UnescapeURLComponent(url_path, 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS); 339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) size_t skip = file_path.find_first_not_of("/\\"); 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (skip != file_path.npos) 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) file_path = file_path.substr(skip); 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::FilePath path = base::FilePath::FromUTF8Unsafe(file_path); 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // It's still possible for someone to construct an annoying URL whose path 346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // would still wind up not being considered relative at this point. 347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // For example: chrome-extension://id/c:////foo.html 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (path.IsAbsolute()) 349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::FilePath(); 350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return path; 352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)base::FilePath ExtensionResourceURLToFilePath(const GURL& url, 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::FilePath& root) { 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string host = net::UnescapeURLComponent(url.host(), 357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS); 358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (host.empty()) 359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::FilePath(); 360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::FilePath relative_path = ExtensionURLToRelativeFilePath(url); 362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (relative_path.empty()) 363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::FilePath(); 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::FilePath path = root.AppendASCII(host).Append(relative_path); 366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!base::PathExists(path)) 367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::FilePath(); 368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) path = base::MakeAbsoluteFilePath(path); 369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (path.empty() || !root.IsParent(path)) 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::FilePath(); 371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return path; 372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 374c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool ValidateExtensionIconSet(const ExtensionIconSet& icon_set, 375c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const Extension* extension, 376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int error_message_id, 377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::string* error) { 378c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch for (ExtensionIconSet::IconMap::const_iterator iter = icon_set.map().begin(); 379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch iter != icon_set.map().end(); 380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch ++iter) { 381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const base::FilePath path = 382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch extension->GetResource(iter->second).GetFilePath(); 383c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!ValidateFilePath(path)) { 384c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *error = l10n_util::GetStringFUTF8(error_message_id, 385c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::UTF8ToUTF16(iter->second)); 386c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return false; 387c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 388c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 389c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return true; 390c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 391c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 392c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochMessageBundle* LoadMessageBundle( 393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const base::FilePath& extension_path, 394c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& default_locale, 395c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::string* error) { 396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch error->clear(); 397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Load locale information if available. 398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::FilePath locale_path = extension_path.Append(kLocaleFolder); 399c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!base::PathExists(locale_path)) 400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return NULL; 401c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 402c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::set<std::string> locales; 403c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!extension_l10n_util::GetValidLocales(locale_path, &locales, error)) 404c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return NULL; 405c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 406c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (default_locale.empty() || locales.find(default_locale) == locales.end()) { 407c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *error = l10n_util::GetStringUTF8( 408c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED); 409c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return NULL; 410c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 411c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 412c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch MessageBundle* message_bundle = 413c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch extension_l10n_util::LoadMessageCatalogs( 414c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch locale_path, 415c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch default_locale, 416c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch extension_l10n_util::CurrentLocaleOrDefault(), 417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch locales, 418c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch error); 419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return message_bundle; 421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 422c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 423c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstd::map<std::string, std::string>* LoadMessageBundleSubstitutionMap( 424c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const base::FilePath& extension_path, 425c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& extension_id, 426c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& default_locale) { 427c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::map<std::string, std::string>* return_value = 428c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch new std::map<std::string, std::string>(); 429c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!default_locale.empty()) { 430c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Touch disk only if extension is localized. 431c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::string error; 432c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<MessageBundle> bundle( 433c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch LoadMessageBundle(extension_path, default_locale, &error)); 434c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 435c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (bundle.get()) 436c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *return_value = *bundle->dictionary(); 437c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 438c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 439c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Add @@extension_id reserved message here, so it's available to 440c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // non-localized extensions too. 441c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return_value->insert( 442c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::make_pair(MessageBundle::kExtensionIdKey, extension_id)); 443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 444c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return return_value; 445c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 446c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 447cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::FilePath GetVerifiedContentsPath(const base::FilePath& extension_path) { 448cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return extension_path.Append(kMetadataFolder) 449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) .Append(kVerifiedContentsFilename); 450cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 451cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::FilePath GetComputedHashesPath(const base::FilePath& extension_path) { 452cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return extension_path.Append(kMetadataFolder).Append(kComputedHashesFilename); 453cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 454cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace file_util 456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace extensions 457