summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/external_pref_extension_loader.cc
blob: 8e291f150c89e445ccefa11436016957a3a9f6f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/external_pref_extension_loader.h"

#include "base/bind.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;

namespace {

// Caller takes ownership of the returned dictionary.
DictionaryValue* ExtractPrefs(const FilePath& path,
                              base::ValueSerializer* serializer) {
  std::string error_msg;
  Value* extensions = serializer->Deserialize(NULL, &error_msg);
  if (!extensions) {
    LOG(WARNING) << "Unable to deserialize json data: " << error_msg
                 << " In file " << path.value() << " .";
  } else {
    if (!extensions->IsType(Value::TYPE_DICTIONARY)) {
      LOG(WARNING) << "Expected a JSON dictionary in file "
                   << path.value() << " .";
    } else {
      return static_cast<DictionaryValue*>(extensions);
    }
  }
  return new DictionaryValue;
}

}  // namespace

ExternalPrefExtensionLoader::ExternalPrefExtensionLoader(int base_path_key,
                                                         Options options)
    : base_path_key_(base_path_key),
      options_(options){
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

const FilePath ExternalPrefExtensionLoader::GetBaseCrxFilePath() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // |base_path_| was set in LoadOnFileThread().
  return base_path_;
}

void ExternalPrefExtensionLoader::StartLoading() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&ExternalPrefExtensionLoader::LoadOnFileThread, this));
}

DictionaryValue* ExternalPrefExtensionLoader::ReadJsonPrefsFile() {
  // TODO(skerner): Some values of base_path_key_ will cause
  // PathService::Get() to return false, because the path does
  // not exist.  Find and fix the build/install scripts so that
  // this can become a CHECK().  Known examples include chrome
  // OS developer builds and linux install packages.
  // Tracked as crbug.com/70402 .
  if (!PathService::Get(base_path_key_, &base_path_)) {
    return NULL;
  }

  FilePath json_file = base_path_.Append(
      FILE_PATH_LITERAL("external_extensions.json"));

  if (!file_util::PathExists(json_file)) {
    // This is not an error.  The file does not exist by default.
    return NULL;
  }

  if (IsOptionSet(ENSURE_PATH_CONTROLLED_BY_ADMIN)) {
#if defined(OS_MACOSX)
    if (!file_util::VerifyPathControlledByAdmin(json_file)) {
      LOG(ERROR) << "Can not read external extensions source.  The file "
                 << json_file.value() << " and every directory in its path, "
                 << "must be owned by root, have group \"admin\", and not be "
                 << "writable by all users. These restrictions prevent "
                 << "unprivleged users from making chrome install extensions "
                 << "on other users' accounts.";
      return NULL;
    }
#else
    // The only platform that uses this check is Mac OS.  If you add one,
    // you need to implement file_util::VerifyPathControlledByAdmin() for
    // that platform.
    NOTREACHED();
#endif  // defined(OS_MACOSX)
  }

  JSONFileValueSerializer serializer(json_file);
  DictionaryValue* parsed_json_prefs = ExtractPrefs(json_file, &serializer);
  return parsed_json_prefs;
}

void ExternalPrefExtensionLoader::LoadOnFileThread() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  prefs_.reset(ReadJsonPrefsFile());
  if (!prefs_.get())
    prefs_.reset(new DictionaryValue());

  if (base_path_key_ == chrome::DIR_EXTERNAL_EXTENSIONS) {
    UMA_HISTOGRAM_COUNTS_100("Extensions.ExternalJsonCount",
                             prefs_->size());
  }

  // If we have any records to process, then we must have
  // read the .json file.  If we read the .json file, then
  // we were should have set |base_path_|.
  if (!prefs_->empty())
    CHECK(!base_path_.empty());

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalPrefExtensionLoader::LoadFinished, this));
}

ExternalTestingExtensionLoader::ExternalTestingExtensionLoader(
    const std::string& json_data,
    const FilePath& fake_base_path)
    : fake_base_path_(fake_base_path) {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  JSONStringValueSerializer serializer(json_data);
  FilePath fake_json_path = fake_base_path.AppendASCII("fake.json");
  testing_prefs_.reset(ExtractPrefs(fake_json_path, &serializer));
}

void ExternalTestingExtensionLoader::StartLoading() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  prefs_.reset(testing_prefs_->DeepCopy());
  LoadFinished();
}

ExternalTestingExtensionLoader::~ExternalTestingExtensionLoader() {}

const FilePath ExternalTestingExtensionLoader::GetBaseCrxFilePath() {
  return fake_base_path_;
}