buffet_config.cc revision e709fa7586dfd3fb8fd41cede0cd5dbc39b31acb
1// Copyright 2015 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "buffet/buffet_config.h"
16
17#include <map>
18#include <set>
19
20#include <base/files/file_util.h>
21#include <base/files/important_file_writer.h>
22#include <base/logging.h>
23#include <base/message_loop/message_loop.h>
24#include <base/strings/string_number_conversions.h>
25#include <brillo/errors/error.h>
26#include <brillo/errors/error_codes.h>
27#include <brillo/osrelease_reader.h>
28#include <brillo/strings/string_utils.h>
29#include <weave/enum_to_string.h>
30
31namespace buffet {
32
33namespace {
34
35const char kErrorDomain[] = "buffet";
36const char kFileReadError[] = "file_read_error";
37const char kProductVersionKey[] = "product_version";
38
39class DefaultFileIO : public BuffetConfig::FileIO {
40 public:
41  bool ReadFile(const base::FilePath& path, std::string* content) override {
42    return base::ReadFileToString(path, content);
43  }
44  bool WriteFile(const base::FilePath& path,
45                 const std::string& content) override {
46    return base::ImportantFileWriter::WriteFileAtomically(path, content);
47  }
48};
49
50}  // namespace
51
52namespace config_keys {
53
54const char kClientId[] = "client_id";
55const char kClientSecret[] = "client_secret";
56const char kApiKey[] = "api_key";
57const char kOAuthURL[] = "oauth_url";
58const char kServiceURL[] = "service_url";
59const char kName[] = "name";
60const char kDescription[] = "description";
61const char kLocation[] = "location";
62const char kLocalAnonymousAccessRole[] = "local_anonymous_access_role";
63const char kLocalDiscoveryEnabled[] = "local_discovery_enabled";
64const char kLocalPairingEnabled[] = "local_pairing_enabled";
65const char kOemName[] = "oem_name";
66const char kModelName[] = "model_name";
67const char kModelId[] = "model_id";
68const char kWifiAutoSetupEnabled[] = "wifi_auto_setup_enabled";
69const char kEmbeddedCode[] = "embedded_code";
70const char kPairingModes[] = "pairing_modes";
71
72}  // namespace config_keys
73
74BuffetConfig::BuffetConfig(const Options& options)
75    : options_(options),
76      default_encryptor_(Encryptor::CreateDefaultEncryptor()),
77      encryptor_(default_encryptor_.get()),
78      default_file_io_(new DefaultFileIO),
79      file_io_(default_file_io_.get()) {}
80
81bool BuffetConfig::LoadDefaults(weave::Settings* settings) {
82  // Keep this hardcoded default for sometime. This previously was set by
83  // libweave. It should be set by overlay's buffet.conf.
84  // Keys owners: avakulenko, gene, vitalybuka.
85  settings->client_id =
86      "338428340000-vkb4p6h40c7kja1k3l70kke8t615cjit.apps.googleusercontent."
87      "com";
88  settings->client_secret = "LS_iPYo_WIOE0m2VnLdduhnx";
89  settings->api_key = "AIzaSyACK3oZtmIylUKXiTMqkZqfuRiCgQmQSAQ";
90
91  settings->name = "Developer device";
92  settings->oem_name = "Chromium";
93  settings->model_name = "Brillo";
94  settings->model_id = "AAAAA";
95
96  if (!base::PathExists(options_.defaults))
97    return true;  // Nothing to load.
98
99  brillo::KeyValueStore store;
100  if (!store.Load(options_.defaults))
101    return false;
102  bool result = LoadDefaults(store, settings);
103  settings->disable_security = options_.disable_security;
104  settings->test_privet_ssid = options_.test_privet_ssid;
105
106  if (!options_.client_id.empty())
107    settings->client_id = options_.client_id;
108  if (!options_.client_secret.empty())
109    settings->client_secret = options_.client_secret;
110  if (!options_.api_key.empty())
111    settings->api_key = options_.api_key;
112  if (!options_.oauth_url.empty())
113    settings->oauth_url = options_.oauth_url;
114  if (!options_.service_url.empty())
115    settings->service_url = options_.service_url;
116
117  return result;
118}
119
120bool BuffetConfig::LoadDefaults(const brillo::KeyValueStore& store,
121                                weave::Settings* settings) {
122  store.GetString(config_keys::kClientId, &settings->client_id);
123  store.GetString(config_keys::kClientSecret, &settings->client_secret);
124  store.GetString(config_keys::kApiKey, &settings->api_key);
125  store.GetString(config_keys::kOAuthURL, &settings->oauth_url);
126  store.GetString(config_keys::kServiceURL, &settings->service_url);
127  store.GetString(config_keys::kOemName, &settings->oem_name);
128  store.GetString(config_keys::kModelName, &settings->model_name);
129  store.GetString(config_keys::kModelId, &settings->model_id);
130
131  brillo::OsReleaseReader reader;
132  reader.Load();
133  if (!reader.GetString(kProductVersionKey, &settings->firmware_version)) {
134    LOG(ERROR) << "Could not read '" << kProductVersionKey << "' from OS";
135  }
136
137  store.GetBoolean(config_keys::kWifiAutoSetupEnabled,
138                   &settings->wifi_auto_setup_enabled);
139  store.GetString(config_keys::kEmbeddedCode, &settings->embedded_code);
140
141  std::string modes_str;
142  if (store.GetString(config_keys::kPairingModes, &modes_str)) {
143    std::set<weave::PairingType> pairing_modes;
144    for (const std::string& mode :
145         brillo::string_utils::Split(modes_str, ",", true, true)) {
146      weave::PairingType pairing_mode;
147      if (!StringToEnum(mode, &pairing_mode))
148        return false;
149      pairing_modes.insert(pairing_mode);
150    }
151    settings->pairing_modes = std::move(pairing_modes);
152  }
153
154  store.GetString(config_keys::kName, &settings->name);
155  store.GetString(config_keys::kDescription, &settings->description);
156  store.GetString(config_keys::kLocation, &settings->location);
157
158  std::string role_str;
159  if (store.GetString(config_keys::kLocalAnonymousAccessRole, &role_str)) {
160    if (!StringToEnum(role_str, &settings->local_anonymous_access_role))
161      return false;
162  }
163  store.GetBoolean(config_keys::kLocalDiscoveryEnabled,
164                   &settings->local_discovery_enabled);
165  store.GetBoolean(config_keys::kLocalPairingEnabled,
166                   &settings->local_pairing_enabled);
167  return true;
168}
169
170std::string BuffetConfig::LoadSettings(const std::string& name) {
171  std::string settings_blob;
172  base::FilePath path = CreatePath(name);
173  if (!file_io_->ReadFile(path, &settings_blob)) {
174    LOG(WARNING) << "Failed to read \'" + path.value() +
175                        "\', proceeding with empty settings.";
176    return std::string();
177  }
178  std::string json_string;
179  if (!encryptor_->DecryptWithAuthentication(settings_blob, &json_string)) {
180    LOG(WARNING)
181        << "Failed to decrypt settings, proceeding with empty settings.";
182    SaveSettings(std::string(), name, {});
183    return std::string();
184  }
185  return json_string;
186}
187
188std::string BuffetConfig::LoadSettings() {
189  return LoadSettings("");
190}
191
192void BuffetConfig::SaveSettings(const std::string& name,
193                                const std::string& settings,
194                                const weave::DoneCallback& callback) {
195  std::string encrypted_settings;
196  weave::ErrorPtr error;
197  base::FilePath path = CreatePath(name);
198  if (!encryptor_->EncryptWithAuthentication(settings, &encrypted_settings)) {
199    weave::Error::AddTo(&error, FROM_HERE, "file_write_error",
200                        "Failed to encrypt settings.");
201    encrypted_settings.clear();
202  }
203  if (!file_io_->WriteFile(path, encrypted_settings)) {
204    weave::Error::AddTo(&error, FROM_HERE, "file_write_error",
205                        "Failed to write \'" + path.value() +
206                            "\', proceeding with empty settings.");
207  }
208  if (!callback.is_null()) {
209    base::MessageLoop::current()->PostTask(
210        FROM_HERE, base::Bind(callback, base::Passed(&error)));
211  }
212}
213
214base::FilePath BuffetConfig::CreatePath(const std::string& name) const {
215  return name.empty() ? options_.settings
216                      : options_.settings.InsertBeforeExtension(
217                            base::FilePath::kExtensionSeparator + name);
218}
219
220bool BuffetConfig::LoadFile(const base::FilePath& file_path,
221                            std::string* data,
222                            brillo::ErrorPtr* error) {
223  if (!file_io_->ReadFile(file_path, data)) {
224    brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
225    brillo::Error::AddToPrintf(error, FROM_HERE, kErrorDomain, kFileReadError,
226                                 "Failed to read file '%s'",
227                                 file_path.value().c_str());
228    return false;
229  }
230  return true;
231}
232
233}  // namespace buffet
234