| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/extensions/external_registry_extension_loader_win.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/file_path.h" | |
| 9 #include "base/file_util.h" | |
| 10 #include "base/memory/scoped_handle.h" | |
| 11 #include "base/metrics/histogram.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "base/time.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "base/values.h" | |
| 16 #include "base/version.h" | |
| 17 #include "base/win/registry.h" | |
| 18 #include "chrome/browser/extensions/external_extension_provider_impl.h" | |
| 19 #include "content/public/browser/browser_thread.h" | |
| 20 | |
| 21 using content::BrowserThread; | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // The Registry subkey that contains information about external extensions. | |
| 26 const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions"; | |
| 27 | |
| 28 // Registry value of of that key that defines the path to the .crx file. | |
| 29 const wchar_t kRegistryExtensionPath[] = L"path"; | |
| 30 | |
| 31 // Registry value of that key that defines the current version of the .crx file. | |
| 32 const wchar_t kRegistryExtensionVersion[] = L"version"; | |
| 33 | |
| 34 bool CanOpenFileForReading(const FilePath& path) { | |
| 35 ScopedStdioHandle file_handle(file_util::OpenFile(path, "rb")); | |
| 36 return file_handle.get() != NULL; | |
| 37 } | |
| 38 | |
| 39 } // namespace | |
| 40 | |
| 41 void ExternalRegistryExtensionLoader::StartLoading() { | |
| 42 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 43 BrowserThread::PostTask( | |
| 44 BrowserThread::FILE, FROM_HERE, | |
| 45 base::Bind(&ExternalRegistryExtensionLoader::LoadOnFileThread, this)); | |
| 46 } | |
| 47 | |
| 48 void ExternalRegistryExtensionLoader::LoadOnFileThread() { | |
| 49 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 50 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 51 scoped_ptr<DictionaryValue> prefs(new DictionaryValue); | |
| 52 | |
| 53 // A map of IDs, to weed out duplicates between HKCU and HKLM. | |
| 54 std::set<string16> keys; | |
| 55 base::win::RegistryKeyIterator iterator_machine_key( | |
| 56 HKEY_LOCAL_MACHINE, ASCIIToWide(kRegistryExtensions).c_str()); | |
| 57 for (; iterator_machine_key.Valid(); ++iterator_machine_key) | |
| 58 keys.insert(iterator_machine_key.Name()); | |
| 59 base::win::RegistryKeyIterator iterator_user_key( | |
| 60 HKEY_CURRENT_USER, ASCIIToWide(kRegistryExtensions).c_str()); | |
| 61 for (; iterator_user_key.Valid(); ++iterator_user_key) | |
| 62 keys.insert(iterator_user_key.Name()); | |
| 63 | |
| 64 // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows | |
| 65 // policy conventions. We only fall back to HKCU if the HKLM key cannot be | |
| 66 // opened, not if the data within the key is invalid, for example. | |
| 67 for (std::set<string16>::const_iterator it = keys.begin(); | |
| 68 it != keys.end(); ++it) { | |
| 69 base::win::RegKey key; | |
| 70 string16 key_path = ASCIIToWide(kRegistryExtensions); | |
| 71 key_path.append(L"\\"); | |
| 72 key_path.append(*it); | |
| 73 if (key.Open(HKEY_LOCAL_MACHINE, | |
| 74 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) { | |
| 75 if (key.Open(HKEY_CURRENT_USER, | |
| 76 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) { | |
| 77 LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): " | |
| 78 << key_path << "."; | |
| 79 continue; | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 string16 extension_path_str; | |
| 84 if (key.ReadValue(kRegistryExtensionPath, &extension_path_str) | |
| 85 != ERROR_SUCCESS) { | |
| 86 // TODO(erikkay): find a way to get this into about:extensions | |
| 87 LOG(ERROR) << "Missing value " << kRegistryExtensionPath | |
| 88 << " for key " << key_path << "."; | |
| 89 continue; | |
| 90 } | |
| 91 | |
| 92 FilePath extension_path(extension_path_str); | |
| 93 if (!extension_path.IsAbsolute()) { | |
| 94 LOG(ERROR) << "File path " << extension_path_str | |
| 95 << " needs to be absolute in key " | |
| 96 << key_path; | |
| 97 continue; | |
| 98 } | |
| 99 | |
| 100 if (!file_util::PathExists(extension_path)) { | |
| 101 LOG(ERROR) << "File " << extension_path_str | |
| 102 << " for key " << key_path | |
| 103 << " does not exist or is not readable."; | |
| 104 continue; | |
| 105 } | |
| 106 | |
| 107 if (!CanOpenFileForReading(extension_path)) { | |
| 108 LOG(ERROR) << "File " << extension_path_str | |
| 109 << " for key " << key_path << " can not be read. " | |
| 110 << "Check that users who should have the extension " | |
| 111 << "installed have permission to read it."; | |
| 112 continue; | |
| 113 } | |
| 114 | |
| 115 string16 extension_version; | |
| 116 if (key.ReadValue(kRegistryExtensionVersion, &extension_version) | |
| 117 != ERROR_SUCCESS) { | |
| 118 // TODO(erikkay): find a way to get this into about:extensions | |
| 119 LOG(ERROR) << "Missing value " << kRegistryExtensionVersion | |
| 120 << " for key " << key_path << "."; | |
| 121 continue; | |
| 122 } | |
| 123 | |
| 124 std::string id = WideToASCII(*it); | |
| 125 StringToLowerASCII(&id); | |
| 126 if (!extensions::Extension::IdIsValid(id)) { | |
| 127 LOG(ERROR) << "Invalid id value " << id | |
| 128 << " for key " << key_path << "."; | |
| 129 continue; | |
| 130 } | |
| 131 | |
| 132 Version version(WideToASCII(extension_version)); | |
| 133 if (!version.IsValid()) { | |
| 134 LOG(ERROR) << "Invalid version value " << extension_version | |
| 135 << " for key " << key_path << "."; | |
| 136 continue; | |
| 137 } | |
| 138 | |
| 139 prefs->SetString( | |
| 140 id + "." + ExternalExtensionProviderImpl::kExternalVersion, | |
| 141 WideToASCII(extension_version)); | |
| 142 prefs->SetString( | |
| 143 id + "." + ExternalExtensionProviderImpl::kExternalCrx, | |
| 144 extension_path_str); | |
| 145 } | |
| 146 | |
| 147 prefs_.reset(prefs.release()); | |
| 148 HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin", | |
| 149 base::TimeTicks::Now() - start_time); | |
| 150 BrowserThread::PostTask( | |
| 151 BrowserThread::UI, FROM_HERE, | |
| 152 base::Bind(&ExternalRegistryExtensionLoader::LoadFinished, this)); | |
| 153 } | |
| OLD | NEW |