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
31 namespace buffet {
32
33 namespace {
34
35 const char kErrorDomain[] = "buffet";
36 const char kFileReadError[] = "file_read_error";
37 const char kProductVersionKey[] = "product_version";
38
39 class DefaultFileIO : public BuffetConfig::FileIO {
40 public:
ReadFile(const base::FilePath & path,std::string * content)41 bool ReadFile(const base::FilePath& path, std::string* content) override {
42 return base::ReadFileToString(path, content);
43 }
WriteFile(const base::FilePath & path,const std::string & content)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
52 namespace config_keys {
53
54 const char kClientId[] = "client_id";
55 const char kClientSecret[] = "client_secret";
56 const char kApiKey[] = "api_key";
57 const char kOAuthURL[] = "oauth_url";
58 const char kServiceURL[] = "service_url";
59 const char kName[] = "name";
60 const char kDescription[] = "description";
61 const char kLocation[] = "location";
62 const char kLocalAnonymousAccessRole[] = "local_anonymous_access_role";
63 const char kLocalDiscoveryEnabled[] = "local_discovery_enabled";
64 const char kLocalPairingEnabled[] = "local_pairing_enabled";
65 const char kOemName[] = "oem_name";
66 const char kModelName[] = "model_name";
67 const char kModelId[] = "model_id";
68 const char kWifiAutoSetupEnabled[] = "wifi_auto_setup_enabled";
69 const char kEmbeddedCode[] = "embedded_code";
70 const char kPairingModes[] = "pairing_modes";
71
72 } // namespace config_keys
73
BuffetConfig(const Options & options)74 BuffetConfig::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
LoadDefaults(weave::Settings * settings)81 bool 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->test_privet_ssid = options_.test_privet_ssid;
104
105 if (!options_.client_id.empty())
106 settings->client_id = options_.client_id;
107 if (!options_.client_secret.empty())
108 settings->client_secret = options_.client_secret;
109 if (!options_.api_key.empty())
110 settings->api_key = options_.api_key;
111 if (!options_.oauth_url.empty())
112 settings->oauth_url = options_.oauth_url;
113 if (!options_.service_url.empty())
114 settings->service_url = options_.service_url;
115
116 return result;
117 }
118
LoadDefaults(const brillo::KeyValueStore & store,weave::Settings * settings)119 bool BuffetConfig::LoadDefaults(const brillo::KeyValueStore& store,
120 weave::Settings* settings) {
121 store.GetString(config_keys::kClientId, &settings->client_id);
122 store.GetString(config_keys::kClientSecret, &settings->client_secret);
123 store.GetString(config_keys::kApiKey, &settings->api_key);
124 store.GetString(config_keys::kOAuthURL, &settings->oauth_url);
125 store.GetString(config_keys::kServiceURL, &settings->service_url);
126 store.GetString(config_keys::kOemName, &settings->oem_name);
127 store.GetString(config_keys::kModelName, &settings->model_name);
128 store.GetString(config_keys::kModelId, &settings->model_id);
129
130 brillo::OsReleaseReader reader;
131 reader.Load();
132 if (!reader.GetString(kProductVersionKey, &settings->firmware_version)) {
133 LOG(ERROR) << "Could not read '" << kProductVersionKey << "' from OS";
134 }
135
136 store.GetBoolean(config_keys::kWifiAutoSetupEnabled,
137 &settings->wifi_auto_setup_enabled);
138 store.GetString(config_keys::kEmbeddedCode, &settings->embedded_code);
139
140 std::string modes_str;
141 if (store.GetString(config_keys::kPairingModes, &modes_str)) {
142 std::set<weave::PairingType> pairing_modes;
143 for (const std::string& mode :
144 brillo::string_utils::Split(modes_str, ",", true, true)) {
145 weave::PairingType pairing_mode;
146 if (!StringToEnum(mode, &pairing_mode))
147 return false;
148 pairing_modes.insert(pairing_mode);
149 }
150 settings->pairing_modes = std::move(pairing_modes);
151 }
152
153 store.GetString(config_keys::kName, &settings->name);
154 store.GetString(config_keys::kDescription, &settings->description);
155 store.GetString(config_keys::kLocation, &settings->location);
156
157 std::string role_str;
158 if (store.GetString(config_keys::kLocalAnonymousAccessRole, &role_str)) {
159 if (!StringToEnum(role_str, &settings->local_anonymous_access_role))
160 return false;
161 }
162 store.GetBoolean(config_keys::kLocalDiscoveryEnabled,
163 &settings->local_discovery_enabled);
164 store.GetBoolean(config_keys::kLocalPairingEnabled,
165 &settings->local_pairing_enabled);
166 return true;
167 }
168
LoadSettings(const std::string & name)169 std::string BuffetConfig::LoadSettings(const std::string& name) {
170 std::string settings_blob;
171 base::FilePath path = CreatePath(name);
172 if (!file_io_->ReadFile(path, &settings_blob)) {
173 LOG(WARNING) << "Failed to read \'" + path.value() +
174 "\', proceeding with empty settings.";
175 return std::string();
176 }
177 std::string json_string;
178 if (!encryptor_->DecryptWithAuthentication(settings_blob, &json_string)) {
179 LOG(WARNING)
180 << "Failed to decrypt settings, proceeding with empty settings.";
181 SaveSettings(std::string(), name, {});
182 return std::string();
183 }
184 return json_string;
185 }
186
LoadSettings()187 std::string BuffetConfig::LoadSettings() {
188 return LoadSettings("");
189 }
190
SaveSettings(const std::string & name,const std::string & settings,const weave::DoneCallback & callback)191 void BuffetConfig::SaveSettings(const std::string& name,
192 const std::string& settings,
193 const weave::DoneCallback& callback) {
194 std::string encrypted_settings;
195 weave::ErrorPtr error;
196 base::FilePath path = CreatePath(name);
197 if (!encryptor_->EncryptWithAuthentication(settings, &encrypted_settings)) {
198 weave::Error::AddTo(&error, FROM_HERE, "file_write_error",
199 "Failed to encrypt settings.");
200 encrypted_settings.clear();
201 }
202 if (!file_io_->WriteFile(path, encrypted_settings)) {
203 weave::Error::AddTo(&error, FROM_HERE, "file_write_error",
204 "Failed to write \'" + path.value() +
205 "\', proceeding with empty settings.");
206 }
207 if (!callback.is_null()) {
208 base::MessageLoop::current()->PostTask(
209 FROM_HERE, base::Bind(callback, base::Passed(&error)));
210 }
211 }
212
CreatePath(const std::string & name) const213 base::FilePath BuffetConfig::CreatePath(const std::string& name) const {
214 return name.empty() ? options_.settings
215 : options_.settings.InsertBeforeExtension(
216 base::FilePath::kExtensionSeparator + name);
217 }
218
LoadFile(const base::FilePath & file_path,std::string * data,brillo::ErrorPtr * error)219 bool BuffetConfig::LoadFile(const base::FilePath& file_path,
220 std::string* data,
221 brillo::ErrorPtr* error) {
222 if (!file_io_->ReadFile(file_path, data)) {
223 brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
224 brillo::Error::AddToPrintf(error, FROM_HERE, kErrorDomain, kFileReadError,
225 "Failed to read file '%s'",
226 file_path.value().c_str());
227 return false;
228 }
229 return true;
230 }
231
232 } // namespace buffet
233