1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/external_registry_extension_loader_win.h"
6
7#include "base/file_path.h"
8#include "base/string_util.h"
9#include "base/utf_string_conversions.h"
10#include "base/values.h"
11#include "base/version.h"
12#include "base/win/registry.h"
13#include "content/browser/browser_thread.h"
14#include "chrome/browser/extensions/external_extension_provider_impl.h"
15
16namespace {
17
18// The Registry hive where to look for external extensions.
19const HKEY kRegRoot = HKEY_LOCAL_MACHINE;
20
21// The Registry subkey that contains information about external extensions.
22const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions";
23
24// Registry value of of that key that defines the path to the .crx file.
25const wchar_t kRegistryExtensionPath[] = L"path";
26
27// Registry value of that key that defines the current version of the .crx file.
28const wchar_t kRegistryExtensionVersion[] = L"version";
29
30}  // namespace
31
32void ExternalRegistryExtensionLoader::StartLoading() {
33  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
34  BrowserThread::PostTask(
35      BrowserThread::FILE, FROM_HERE,
36      NewRunnableMethod(
37          this,
38          &ExternalRegistryExtensionLoader::LoadOnFileThread));
39}
40
41void ExternalRegistryExtensionLoader::LoadOnFileThread() {
42  CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
43  scoped_ptr<DictionaryValue> prefs(new DictionaryValue);
44
45  base::win::RegistryKeyIterator iterator(
46      kRegRoot, ASCIIToWide(kRegistryExtensions).c_str());
47  while (iterator.Valid()) {
48    base::win::RegKey key;
49    std::wstring key_path = ASCIIToWide(kRegistryExtensions);
50    key_path.append(L"\\");
51    key_path.append(iterator.Name());
52    if (key.Open(kRegRoot, key_path.c_str(), KEY_READ)  == ERROR_SUCCESS) {
53      std::wstring extension_path_str;
54      if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
55          == ERROR_SUCCESS) {
56        FilePath extension_path(extension_path_str);
57        if (!extension_path.IsAbsolute()) {
58          LOG(ERROR) << "Path " << extension_path_str
59                     << " needs to be absolute in key "
60                     << key_path;
61          ++iterator;
62          continue;
63        }
64        std::wstring extension_version;
65        if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
66            == ERROR_SUCCESS) {
67          std::string id = WideToASCII(iterator.Name());
68          StringToLowerASCII(&id);
69
70          if (!Extension::IdIsValid(id)) {
71            LOG(ERROR) << "Invalid id value " << id
72                       << " for key " << key_path << " .";
73            ++iterator;
74            continue;
75          }
76
77          scoped_ptr<Version> version;
78          version.reset(Version::GetVersionFromString(
79                            WideToASCII(extension_version)));
80          if (!version.get()) {
81            LOG(ERROR) << "Invalid version value " << extension_version
82                       << " for key " << key_path << " .";
83            ++iterator;
84            continue;
85          }
86
87          prefs->SetString(
88              id + "." + ExternalExtensionProviderImpl::kExternalVersion,
89              WideToASCII(extension_version));
90          prefs->SetString(
91              id + "." + ExternalExtensionProviderImpl::kExternalCrx,
92              extension_path_str);
93        } else {
94          // TODO(erikkay): find a way to get this into about:extensions
95          LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
96                     << " for key " << key_path << " .";
97        }
98      } else {
99        // TODO(erikkay): find a way to get this into about:extensions
100        LOG(ERROR) << "Missing value " << kRegistryExtensionPath
101                   << " for key " << key_path << " .";
102      }
103    }
104    ++iterator;
105  }
106
107  prefs_.reset(prefs.release());
108  BrowserThread::PostTask(
109      BrowserThread::UI, FROM_HERE,
110      NewRunnableMethod(
111          this,
112          &ExternalRegistryExtensionLoader::LoadFinished));
113}
114