Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / external_registry_loader_win.cc
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_loader_win.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_file.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "base/version.h"
18 #include "base/win/registry.h"
19 #include "chrome/browser/extensions/external_provider_impl.h"
20 #include "components/crx_file/id_util.h"
21 #include "content/public/browser/browser_thread.h"
22
23 using content::BrowserThread;
24
25 namespace {
26
27 // The Registry subkey that contains information about external extensions.
28 const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions";
29
30 // Registry value of the key that defines the installation parameter.
31 const wchar_t kRegistryExtensionInstallParam[] = L"install_parameter";
32
33 // Registry value of the key that defines the path to the .crx file.
34 const wchar_t kRegistryExtensionPath[] = L"path";
35
36 // Registry value of that key that defines the current version of the .crx file.
37 const wchar_t kRegistryExtensionVersion[] = L"version";
38
39 // Registry value of the key that defines an external update URL.
40 const wchar_t kRegistryExtensionUpdateUrl[] = L"update_url";
41
42 bool CanOpenFileForReading(const base::FilePath& path) {
43   base::ScopedFILE file_handle(base::OpenFile(path, "rb"));
44   return file_handle.get() != NULL;
45 }
46
47 std::string MakePrefName(const std::string& extension_id,
48                          const std::string& pref_name) {
49   return base::StringPrintf("%s.%s", extension_id.c_str(), pref_name.c_str());
50 }
51
52 }  // namespace
53
54 namespace extensions {
55
56 void ExternalRegistryLoader::StartLoading() {
57   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58   BrowserThread::PostTask(
59       BrowserThread::FILE, FROM_HERE,
60       base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this));
61 }
62
63 void ExternalRegistryLoader::LoadOnFileThread() {
64   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
65   base::TimeTicks start_time = base::TimeTicks::Now();
66   scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
67
68   // A map of IDs, to weed out duplicates between HKCU and HKLM.
69   std::set<base::string16> keys;
70   base::win::RegistryKeyIterator iterator_machine_key(
71       HKEY_LOCAL_MACHINE,
72       base::ASCIIToWide(kRegistryExtensions).c_str(),
73       KEY_WOW64_32KEY);
74   for (; iterator_machine_key.Valid(); ++iterator_machine_key)
75     keys.insert(iterator_machine_key.Name());
76   base::win::RegistryKeyIterator iterator_user_key(
77       HKEY_CURRENT_USER, base::ASCIIToWide(kRegistryExtensions).c_str());
78   for (; iterator_user_key.Valid(); ++iterator_user_key)
79     keys.insert(iterator_user_key.Name());
80
81   // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows
82   // policy conventions. We only fall back to HKCU if the HKLM key cannot be
83   // opened, not if the data within the key is invalid, for example.
84   for (std::set<base::string16>::const_iterator it = keys.begin();
85        it != keys.end(); ++it) {
86     base::win::RegKey key;
87     base::string16 key_path = base::ASCIIToWide(kRegistryExtensions);
88     key_path.append(L"\\");
89     key_path.append(*it);
90     if (key.Open(HKEY_LOCAL_MACHINE,
91                  key_path.c_str(),
92                  KEY_READ | KEY_WOW64_32KEY) != ERROR_SUCCESS &&
93         key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ) !=
94             ERROR_SUCCESS) {
95       LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): "
96                  << key_path << ".";
97       continue;
98     }
99
100     std::string id = base::UTF16ToASCII(*it);
101     base::StringToLowerASCII(&id);
102     if (!crx_file::id_util::IdIsValid(id)) {
103       LOG(ERROR) << "Invalid id value " << id
104                  << " for key " << key_path << ".";
105       continue;
106     }
107
108     base::string16 extension_dist_id;
109     if (key.ReadValue(kRegistryExtensionInstallParam, &extension_dist_id) ==
110         ERROR_SUCCESS) {
111       prefs->SetString(MakePrefName(id, ExternalProviderImpl::kInstallParam),
112                        base::UTF16ToASCII(extension_dist_id));
113     }
114
115     // If there is an update URL present, copy it to prefs and ignore
116     // path and version keys for this entry.
117     base::string16 extension_update_url;
118     if (key.ReadValue(kRegistryExtensionUpdateUrl, &extension_update_url)
119         == ERROR_SUCCESS) {
120       prefs->SetString(
121           MakePrefName(id, ExternalProviderImpl::kExternalUpdateUrl),
122           base::UTF16ToASCII(extension_update_url));
123       continue;
124     }
125
126     base::string16 extension_path_str;
127     if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
128         != ERROR_SUCCESS) {
129       // TODO(erikkay): find a way to get this into about:extensions
130       LOG(ERROR) << "Missing value " << kRegistryExtensionPath
131                  << " for key " << key_path << ".";
132       continue;
133     }
134
135     base::FilePath extension_path(extension_path_str);
136     if (!extension_path.IsAbsolute()) {
137       LOG(ERROR) << "File path " << extension_path_str
138                  << " needs to be absolute in key "
139                  << key_path;
140       continue;
141     }
142
143     if (!base::PathExists(extension_path)) {
144       LOG(ERROR) << "File " << extension_path_str
145                  << " for key " << key_path
146                  << " does not exist or is not readable.";
147       continue;
148     }
149
150     if (!CanOpenFileForReading(extension_path)) {
151       LOG(ERROR) << "File " << extension_path_str
152                  << " for key " << key_path << " can not be read. "
153                  << "Check that users who should have the extension "
154                  << "installed have permission to read it.";
155       continue;
156     }
157
158     base::string16 extension_version;
159     if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
160         != ERROR_SUCCESS) {
161       // TODO(erikkay): find a way to get this into about:extensions
162       LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
163                  << " for key " << key_path << ".";
164       continue;
165     }
166
167     Version version(base::UTF16ToASCII(extension_version));
168     if (!version.IsValid()) {
169       LOG(ERROR) << "Invalid version value " << extension_version
170                  << " for key " << key_path << ".";
171       continue;
172     }
173
174     prefs->SetString(
175         MakePrefName(id, ExternalProviderImpl::kExternalVersion),
176         base::UTF16ToASCII(extension_version));
177     prefs->SetString(
178         MakePrefName(id, ExternalProviderImpl::kExternalCrx),
179         extension_path_str);
180     prefs->SetBoolean(
181         MakePrefName(id, ExternalProviderImpl::kMayBeUntrusted),
182         true);
183   }
184
185   prefs_.reset(prefs.release());
186   LOCAL_HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
187                         base::TimeTicks::Now() - start_time);
188   BrowserThread::PostTask(
189       BrowserThread::UI, FROM_HERE,
190       base::Bind(&ExternalRegistryLoader::LoadFinished, this));
191 }
192
193 }  // namespace extensions