blob: 44d20dde2738849d776898c0db654e5ab7222dbb [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Vitaly Bukad322a3c2015-08-16 01:03:02 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/config.h"
Vitaly Bukad322a3c2015-08-16 01:03:02 -07006
7#include <set>
8
Vitaly Bukac11a17d2015-08-15 10:36:10 -07009#include <base/bind.h>
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070010#include <base/guid.h>
Vitaly Bukac11a17d2015-08-15 10:36:10 -070011#include <base/json/json_reader.h>
12#include <base/json/json_writer.h>
Vitaly Bukad322a3c2015-08-16 01:03:02 -070013#include <base/logging.h>
14#include <base/strings/string_number_conversions.h>
Vitaly Bukac11a17d2015-08-15 10:36:10 -070015#include <base/values.h>
Vitaly Bukad322a3c2015-08-16 01:03:02 -070016#include <weave/enum_to_string.h>
17
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080018#include "src/data_encoding.h"
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020019#include "src/privet/privet_types.h"
20#include "src/string_utils.h"
Vitaly Bukaac18fcf2016-01-15 14:48:54 -080021#include "src/bind_lambda.h"
Vitaly Bukad322a3c2015-08-16 01:03:02 -070022
Vitaly Bukad322a3c2015-08-16 01:03:02 -070023namespace weave {
24
Vitaly Bukad1e6c4f2016-01-15 12:19:17 -080025const char kConfigName[] = "config";
26
Vitaly Bukad322a3c2015-08-16 01:03:02 -070027namespace config_keys {
28
Vitaly Bukabced5af2015-10-12 17:42:30 -070029const char kVersion[] = "version";
30
Vitaly Bukad322a3c2015-08-16 01:03:02 -070031const char kClientId[] = "client_id";
32const char kClientSecret[] = "client_secret";
33const char kApiKey[] = "api_key";
34const char kOAuthURL[] = "oauth_url";
35const char kServiceURL[] = "service_url";
36const char kName[] = "name";
37const char kDescription[] = "description";
38const char kLocation[] = "location";
39const char kLocalAnonymousAccessRole[] = "local_anonymous_access_role";
40const char kLocalDiscoveryEnabled[] = "local_discovery_enabled";
41const char kLocalPairingEnabled[] = "local_pairing_enabled";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070042const char kRefreshToken[] = "refresh_token";
Johan Euphrosine312c2f52015-09-29 00:04:29 -070043const char kCloudId[] = "cloud_id";
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070044const char kDeviceId[] = "device_id";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070045const char kRobotAccount[] = "robot_account";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070046const char kLastConfiguredSsid[] = "last_configured_ssid";
Vitaly Buka8589b052015-09-29 00:46:14 -070047const char kSecret[] = "secret";
Vitaly Buka63c98622015-12-11 11:06:04 -080048const char kRootClientTokenOwner[] = "root_client_token_owner";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070049
50} // namespace config_keys
51
Vitaly Buka0d7aac82015-11-16 23:02:24 -080052const char kWeaveUrl[] = "https://www.googleapis.com/weave/v1/";
53const char kDeprecatedUrl[] = "https://www.googleapis.com/clouddevices/v1/";
54
Vitaly Bukac11a17d2015-08-15 10:36:10 -070055namespace {
56
Vitaly Bukabced5af2015-10-12 17:42:30 -070057const int kCurrentConfigVersion = 1;
58
59void MigrateFromV0(base::DictionaryValue* dict) {
60 std::string cloud_id;
61 if (dict->GetString(config_keys::kCloudId, &cloud_id) && !cloud_id.empty())
62 return;
63 scoped_ptr<base::Value> tmp;
64 if (dict->Remove(config_keys::kDeviceId, &tmp))
65 dict->Set(config_keys::kCloudId, std::move(tmp));
66}
67
Vitaly Buka238db692015-09-29 16:58:39 -070068Config::Settings CreateDefaultSettings() {
69 Config::Settings result;
Vitaly Bukad322a3c2015-08-16 01:03:02 -070070 result.oauth_url = "https://accounts.google.com/o/oauth2/";
Vitaly Buka0d7aac82015-11-16 23:02:24 -080071 result.service_url = kWeaveUrl;
Vitaly Bukab624bc42015-09-29 19:13:55 -070072 result.local_anonymous_access_role = AuthScope::kViewer;
Vitaly Buka52d006a2015-11-21 17:14:51 -080073 result.pairing_modes.insert(PairingType::kPinCode);
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070074 result.device_id = base::GenerateGUID();
Vitaly Bukad322a3c2015-08-16 01:03:02 -070075 return result;
76}
77
Vitaly Buka63c98622015-12-11 11:06:04 -080078const EnumToStringMap<RootClientTokenOwner>::Map kRootClientTokenOwnerMap[] = {
79 {RootClientTokenOwner::kNone, "none"},
80 {RootClientTokenOwner::kClient, "client"},
81 {RootClientTokenOwner::kCloud, "cloud"},
82};
83
Vitaly Bukac11a17d2015-08-15 10:36:10 -070084} // namespace
Vitaly Bukad322a3c2015-08-16 01:03:02 -070085
Vitaly Buka63c98622015-12-11 11:06:04 -080086template <>
87LIBWEAVE_EXPORT EnumToStringMap<RootClientTokenOwner>::EnumToStringMap()
88 : EnumToStringMap(kRootClientTokenOwnerMap) {}
89
Vitaly Buka1e363672015-09-25 14:01:16 -070090Config::Config(provider::ConfigStore* config_store)
Vitaly Buka3d6b5522015-12-22 13:14:16 -080091 : settings_{CreateDefaultSettings()}, config_store_{config_store} {
92 Load();
93}
Vitaly Bukad322a3c2015-08-16 01:03:02 -070094
95void Config::AddOnChangedCallback(const OnChangedCallback& callback) {
96 on_changed_.push_back(callback);
97 // Force to read current state.
98 callback.Run(settings_);
99}
100
Vitaly Buka238db692015-09-29 16:58:39 -0700101const Config::Settings& Config::GetSettings() const {
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700102 return settings_;
103}
104
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700105void Config::Load() {
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700106 Transaction change{this};
107 change.save_ = false;
108
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700109 settings_ = CreateDefaultSettings();
110
111 if (!config_store_)
112 return;
113
114 // Crash on any mistakes in defaults.
115 CHECK(config_store_->LoadDefaults(&settings_));
116
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700117 CHECK(!settings_.client_id.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700118 CHECK(!settings_.client_secret.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700119 CHECK(!settings_.api_key.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700120 CHECK(!settings_.oauth_url.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700121 CHECK(!settings_.service_url.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700122 CHECK(!settings_.oem_name.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700123 CHECK(!settings_.model_name.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700124 CHECK(!settings_.model_id.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700125 CHECK(!settings_.name.empty());
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700126 CHECK(!settings_.device_id.empty());
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800127 CHECK_EQ(settings_.embedded_code.empty(),
128 (settings_.pairing_modes.find(PairingType::kEmbeddedCode) ==
129 settings_.pairing_modes.end()));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700130
Vitaly Buka8589b052015-09-29 00:46:14 -0700131 // Values below will be generated at runtime.
132 CHECK(settings_.cloud_id.empty());
133 CHECK(settings_.refresh_token.empty());
134 CHECK(settings_.robot_account.empty());
135 CHECK(settings_.last_configured_ssid.empty());
136 CHECK(settings_.secret.empty());
Vitaly Buka63c98622015-12-11 11:06:04 -0800137 CHECK(settings_.root_client_token_owner == RootClientTokenOwner::kNone);
Vitaly Buka8589b052015-09-29 00:46:14 -0700138
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700139 change.LoadState();
140}
141
142void Config::Transaction::LoadState() {
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700143 if (!config_->config_store_)
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700144 return;
Vitaly Bukad1e6c4f2016-01-15 12:19:17 -0800145 std::string json_string = config_->config_store_->LoadSettings(kConfigName);
146 if (json_string.empty()) {
147 json_string = config_->config_store_->LoadSettings();
148 if (json_string.empty())
149 return;
150 }
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700151
152 auto value = base::JSONReader::Read(json_string);
Vitaly Bukabced5af2015-10-12 17:42:30 -0700153 base::DictionaryValue* dict = nullptr;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700154 if (!value || !value->GetAsDictionary(&dict)) {
155 LOG(ERROR) << "Failed to parse settings.";
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700156 return;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700157 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700158
Vitaly Bukabced5af2015-10-12 17:42:30 -0700159 int loaded_version = 0;
160 dict->GetInteger(config_keys::kVersion, &loaded_version);
161
162 if (loaded_version != kCurrentConfigVersion) {
163 LOG(INFO) << "State version mismatch. expected: " << kCurrentConfigVersion
164 << ", loaded: " << loaded_version;
165 save_ = true;
166 }
167
168 if (loaded_version == 0) {
169 MigrateFromV0(dict);
170 }
171
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700172 std::string tmp;
173 bool tmp_bool{false};
174
175 if (dict->GetString(config_keys::kClientId, &tmp))
176 set_client_id(tmp);
177
178 if (dict->GetString(config_keys::kClientSecret, &tmp))
179 set_client_secret(tmp);
180
181 if (dict->GetString(config_keys::kApiKey, &tmp))
182 set_api_key(tmp);
183
184 if (dict->GetString(config_keys::kOAuthURL, &tmp))
185 set_oauth_url(tmp);
186
Vitaly Buka0d7aac82015-11-16 23:02:24 -0800187 if (dict->GetString(config_keys::kServiceURL, &tmp)) {
188 if (tmp == kDeprecatedUrl)
189 tmp = kWeaveUrl;
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700190 set_service_url(tmp);
Vitaly Buka0d7aac82015-11-16 23:02:24 -0800191 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700192
193 if (dict->GetString(config_keys::kName, &tmp))
194 set_name(tmp);
195
196 if (dict->GetString(config_keys::kDescription, &tmp))
197 set_description(tmp);
198
199 if (dict->GetString(config_keys::kLocation, &tmp))
200 set_location(tmp);
201
Vitaly Bukab624bc42015-09-29 19:13:55 -0700202 AuthScope scope{AuthScope::kNone};
203 if (dict->GetString(config_keys::kLocalAnonymousAccessRole, &tmp) &&
204 StringToEnum(tmp, &scope)) {
205 set_local_anonymous_access_role(scope);
206 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700207
208 if (dict->GetBoolean(config_keys::kLocalDiscoveryEnabled, &tmp_bool))
209 set_local_discovery_enabled(tmp_bool);
210
211 if (dict->GetBoolean(config_keys::kLocalPairingEnabled, &tmp_bool))
212 set_local_pairing_enabled(tmp_bool);
213
Vitaly Buka8589b052015-09-29 00:46:14 -0700214 if (dict->GetString(config_keys::kCloudId, &tmp))
215 set_cloud_id(tmp);
216
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700217 if (dict->GetString(config_keys::kDeviceId, &tmp))
218 set_device_id(tmp);
219
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700220 if (dict->GetString(config_keys::kRefreshToken, &tmp))
221 set_refresh_token(tmp);
222
223 if (dict->GetString(config_keys::kRobotAccount, &tmp))
224 set_robot_account(tmp);
225
226 if (dict->GetString(config_keys::kLastConfiguredSsid, &tmp))
227 set_last_configured_ssid(tmp);
228
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800229 std::vector<uint8_t> secret;
230 if (dict->GetString(config_keys::kSecret, &tmp) && Base64Decode(tmp, &secret))
231 set_secret(secret);
Vitaly Bukaa5803282015-12-06 20:11:55 -0800232
Vitaly Buka63c98622015-12-11 11:06:04 -0800233 RootClientTokenOwner token_owner{RootClientTokenOwner::kNone};
234 if (dict->GetString(config_keys::kRootClientTokenOwner, &tmp) &&
235 StringToEnum(tmp, &token_owner)) {
236 set_root_client_token_owner(token_owner);
237 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700238}
239
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700240void Config::Save() {
241 if (!config_store_)
242 return;
243
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700244 base::DictionaryValue dict;
Vitaly Bukabced5af2015-10-12 17:42:30 -0700245 dict.SetInteger(config_keys::kVersion, kCurrentConfigVersion);
246
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700247 dict.SetString(config_keys::kClientId, settings_.client_id);
248 dict.SetString(config_keys::kClientSecret, settings_.client_secret);
249 dict.SetString(config_keys::kApiKey, settings_.api_key);
250 dict.SetString(config_keys::kOAuthURL, settings_.oauth_url);
251 dict.SetString(config_keys::kServiceURL, settings_.service_url);
252 dict.SetString(config_keys::kRefreshToken, settings_.refresh_token);
Johan Euphrosine312c2f52015-09-29 00:04:29 -0700253 dict.SetString(config_keys::kCloudId, settings_.cloud_id);
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700254 dict.SetString(config_keys::kDeviceId, settings_.device_id);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700255 dict.SetString(config_keys::kRobotAccount, settings_.robot_account);
256 dict.SetString(config_keys::kLastConfiguredSsid,
257 settings_.last_configured_ssid);
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800258 dict.SetString(config_keys::kSecret, Base64Encode(settings_.secret));
Vitaly Buka63c98622015-12-11 11:06:04 -0800259 dict.SetString(config_keys::kRootClientTokenOwner,
260 EnumToString(settings_.root_client_token_owner));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700261 dict.SetString(config_keys::kName, settings_.name);
262 dict.SetString(config_keys::kDescription, settings_.description);
263 dict.SetString(config_keys::kLocation, settings_.location);
264 dict.SetString(config_keys::kLocalAnonymousAccessRole,
Vitaly Bukab624bc42015-09-29 19:13:55 -0700265 EnumToString(settings_.local_anonymous_access_role));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700266 dict.SetBoolean(config_keys::kLocalDiscoveryEnabled,
267 settings_.local_discovery_enabled);
268 dict.SetBoolean(config_keys::kLocalPairingEnabled,
269 settings_.local_pairing_enabled);
270
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700271 std::string json_string;
272 base::JSONWriter::WriteWithOptions(
273 dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
274
Vitaly Bukaac18fcf2016-01-15 14:48:54 -0800275 config_store_->SaveSettings(
276 kConfigName, json_string,
277 base::Bind([](ErrorPtr error) { CHECK(!error); }));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700278}
279
280Config::Transaction::~Transaction() {
281 Commit();
282}
283
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700284void Config::Transaction::Commit() {
285 if (!config_)
286 return;
287 if (save_)
288 config_->Save();
289 for (const auto& cb : config_->on_changed_)
290 cb.Run(*settings_);
291 config_ = nullptr;
292}
293
294} // namespace weave