blob: 108c6aa167fe68b9bb34a0ed4db69dc1f4bd71b5 [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
Alex Vakulenkob9bbdc62016-03-28 13:26:51 -07007
8#include <algorithm>
Vitaly Bukad322a3c2015-08-16 01:03:02 -07009#include <set>
10
Vitaly Bukac11a17d2015-08-15 10:36:10 -070011#include <base/bind.h>
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070012#include <base/guid.h>
Vitaly Bukac11a17d2015-08-15 10:36:10 -070013#include <base/json/json_reader.h>
14#include <base/json/json_writer.h>
Vitaly Bukad322a3c2015-08-16 01:03:02 -070015#include <base/logging.h>
16#include <base/strings/string_number_conversions.h>
Vitaly Bukac11a17d2015-08-15 10:36:10 -070017#include <base/values.h>
Vitaly Bukad322a3c2015-08-16 01:03:02 -070018#include <weave/enum_to_string.h>
19
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080020#include "src/data_encoding.h"
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020021#include "src/privet/privet_types.h"
22#include "src/string_utils.h"
Vitaly Bukaac18fcf2016-01-15 14:48:54 -080023#include "src/bind_lambda.h"
Vitaly Bukad322a3c2015-08-16 01:03:02 -070024
Vitaly Bukad322a3c2015-08-16 01:03:02 -070025namespace weave {
26
Vitaly Bukad1e6c4f2016-01-15 12:19:17 -080027const char kConfigName[] = "config";
28
Vitaly Bukad322a3c2015-08-16 01:03:02 -070029namespace config_keys {
30
Vitaly Bukabced5af2015-10-12 17:42:30 -070031const char kVersion[] = "version";
32
Vitaly Bukad322a3c2015-08-16 01:03:02 -070033const char kClientId[] = "client_id";
34const char kClientSecret[] = "client_secret";
35const char kApiKey[] = "api_key";
Vitaly Buka1e019fa2016-02-10 11:28:16 -080036const char kOAuthUrl[] = "oauth_url";
37const char kServiceUrl[] = "service_url";
Vitaly Buka3b8fbc52016-02-04 15:42:04 -080038const char kXmppEndpoint[] = "xmpp_endpoint";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070039const char kName[] = "name";
40const char kDescription[] = "description";
41const char kLocation[] = "location";
42const char kLocalAnonymousAccessRole[] = "local_anonymous_access_role";
43const char kLocalDiscoveryEnabled[] = "local_discovery_enabled";
44const char kLocalPairingEnabled[] = "local_pairing_enabled";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070045const char kRefreshToken[] = "refresh_token";
Johan Euphrosine312c2f52015-09-29 00:04:29 -070046const char kCloudId[] = "cloud_id";
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070047const char kDeviceId[] = "device_id";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070048const char kRobotAccount[] = "robot_account";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070049const char kLastConfiguredSsid[] = "last_configured_ssid";
Vitaly Buka8589b052015-09-29 00:46:14 -070050const char kSecret[] = "secret";
Vitaly Buka63c98622015-12-11 11:06:04 -080051const char kRootClientTokenOwner[] = "root_client_token_owner";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070052
53} // namespace config_keys
54
Vitaly Buka0d7aac82015-11-16 23:02:24 -080055const char kWeaveUrl[] = "https://www.googleapis.com/weave/v1/";
56const char kDeprecatedUrl[] = "https://www.googleapis.com/clouddevices/v1/";
Vitaly Buka3b8fbc52016-02-04 15:42:04 -080057const char kXmppEndpoint[] = "talk.google.com:5223";
Vitaly Buka0d7aac82015-11-16 23:02:24 -080058
Vitaly Bukac11a17d2015-08-15 10:36:10 -070059namespace {
60
Vitaly Bukabced5af2015-10-12 17:42:30 -070061const int kCurrentConfigVersion = 1;
62
63void MigrateFromV0(base::DictionaryValue* dict) {
64 std::string cloud_id;
65 if (dict->GetString(config_keys::kCloudId, &cloud_id) && !cloud_id.empty())
66 return;
67 scoped_ptr<base::Value> tmp;
68 if (dict->Remove(config_keys::kDeviceId, &tmp))
69 dict->Set(config_keys::kCloudId, std::move(tmp));
70}
71
Vitaly Buka03ee8ac2016-02-05 11:40:33 -080072Config::Settings CreateDefaultSettings(provider::ConfigStore* config_store) {
Vitaly Buka238db692015-09-29 16:58:39 -070073 Config::Settings result;
Vitaly Bukad322a3c2015-08-16 01:03:02 -070074 result.oauth_url = "https://accounts.google.com/o/oauth2/";
Vitaly Buka0d7aac82015-11-16 23:02:24 -080075 result.service_url = kWeaveUrl;
Vitaly Buka3b8fbc52016-02-04 15:42:04 -080076 result.xmpp_endpoint = kXmppEndpoint;
Vitaly Bukab624bc42015-09-29 19:13:55 -070077 result.local_anonymous_access_role = AuthScope::kViewer;
Vitaly Buka52d006a2015-11-21 17:14:51 -080078 result.pairing_modes.insert(PairingType::kPinCode);
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070079 result.device_id = base::GenerateGUID();
Vitaly Buka03ee8ac2016-02-05 11:40:33 -080080
81 if (!config_store)
82 return result;
83
84 // Crash on any mistakes in defaults.
85 CHECK(config_store->LoadDefaults(&result));
86
87 CHECK(!result.client_id.empty());
88 CHECK(!result.client_secret.empty());
89 CHECK(!result.api_key.empty());
90 CHECK(!result.oauth_url.empty());
91 CHECK(!result.service_url.empty());
92 CHECK(!result.xmpp_endpoint.empty());
93 CHECK(!result.oem_name.empty());
94 CHECK(!result.model_name.empty());
95 CHECK(!result.model_id.empty());
96 CHECK(!result.name.empty());
97 CHECK(!result.device_id.empty());
98 CHECK_EQ(result.embedded_code.empty(),
99 (result.pairing_modes.find(PairingType::kEmbeddedCode) ==
100 result.pairing_modes.end()));
101
102 // Values below will be generated at runtime.
103 CHECK(result.cloud_id.empty());
104 CHECK(result.refresh_token.empty());
105 CHECK(result.robot_account.empty());
106 CHECK(result.last_configured_ssid.empty());
107 CHECK(result.secret.empty());
108 CHECK(result.root_client_token_owner == RootClientTokenOwner::kNone);
109
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700110 return result;
111}
112
Vitaly Buka63c98622015-12-11 11:06:04 -0800113const EnumToStringMap<RootClientTokenOwner>::Map kRootClientTokenOwnerMap[] = {
114 {RootClientTokenOwner::kNone, "none"},
115 {RootClientTokenOwner::kClient, "client"},
116 {RootClientTokenOwner::kCloud, "cloud"},
117};
118
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700119} // namespace
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700120
Vitaly Buka63c98622015-12-11 11:06:04 -0800121template <>
122LIBWEAVE_EXPORT EnumToStringMap<RootClientTokenOwner>::EnumToStringMap()
123 : EnumToStringMap(kRootClientTokenOwnerMap) {}
124
Vitaly Buka1e363672015-09-25 14:01:16 -0700125Config::Config(provider::ConfigStore* config_store)
Vitaly Buka03ee8ac2016-02-05 11:40:33 -0800126 : defaults_{CreateDefaultSettings(config_store)},
127 settings_{defaults_},
128 config_store_{config_store} {
129 Transaction change{this};
130 change.save_ = false;
131 change.LoadState();
Vitaly Buka3d6b5522015-12-22 13:14:16 -0800132}
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700133
134void Config::AddOnChangedCallback(const OnChangedCallback& callback) {
135 on_changed_.push_back(callback);
136 // Force to read current state.
137 callback.Run(settings_);
138}
139
Vitaly Buka238db692015-09-29 16:58:39 -0700140const Config::Settings& Config::GetSettings() const {
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700141 return settings_;
142}
143
Vitaly Buka03ee8ac2016-02-05 11:40:33 -0800144const Config::Settings& Config::GetDefaults() const {
145 return defaults_;
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700146}
147
148void Config::Transaction::LoadState() {
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700149 if (!config_->config_store_)
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700150 return;
Vitaly Bukad1e6c4f2016-01-15 12:19:17 -0800151 std::string json_string = config_->config_store_->LoadSettings(kConfigName);
152 if (json_string.empty()) {
153 json_string = config_->config_store_->LoadSettings();
154 if (json_string.empty())
155 return;
156 }
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700157
158 auto value = base::JSONReader::Read(json_string);
Vitaly Bukabced5af2015-10-12 17:42:30 -0700159 base::DictionaryValue* dict = nullptr;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700160 if (!value || !value->GetAsDictionary(&dict)) {
161 LOG(ERROR) << "Failed to parse settings.";
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700162 return;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700163 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700164
Vitaly Bukabced5af2015-10-12 17:42:30 -0700165 int loaded_version = 0;
166 dict->GetInteger(config_keys::kVersion, &loaded_version);
167
168 if (loaded_version != kCurrentConfigVersion) {
169 LOG(INFO) << "State version mismatch. expected: " << kCurrentConfigVersion
170 << ", loaded: " << loaded_version;
171 save_ = true;
172 }
173
174 if (loaded_version == 0) {
175 MigrateFromV0(dict);
176 }
177
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700178 std::string tmp;
179 bool tmp_bool{false};
180
181 if (dict->GetString(config_keys::kClientId, &tmp))
182 set_client_id(tmp);
183
184 if (dict->GetString(config_keys::kClientSecret, &tmp))
185 set_client_secret(tmp);
186
187 if (dict->GetString(config_keys::kApiKey, &tmp))
188 set_api_key(tmp);
189
Vitaly Buka1e019fa2016-02-10 11:28:16 -0800190 if (dict->GetString(config_keys::kOAuthUrl, &tmp))
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700191 set_oauth_url(tmp);
192
Vitaly Buka1e019fa2016-02-10 11:28:16 -0800193 if (dict->GetString(config_keys::kServiceUrl, &tmp)) {
Vitaly Buka0d7aac82015-11-16 23:02:24 -0800194 if (tmp == kDeprecatedUrl)
195 tmp = kWeaveUrl;
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700196 set_service_url(tmp);
Vitaly Buka0d7aac82015-11-16 23:02:24 -0800197 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700198
Vitaly Buka3b8fbc52016-02-04 15:42:04 -0800199 if (dict->GetString(config_keys::kXmppEndpoint, &tmp)) {
200 set_xmpp_endpoint(tmp);
201 }
202
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700203 if (dict->GetString(config_keys::kName, &tmp))
204 set_name(tmp);
205
206 if (dict->GetString(config_keys::kDescription, &tmp))
207 set_description(tmp);
208
209 if (dict->GetString(config_keys::kLocation, &tmp))
210 set_location(tmp);
211
Vitaly Bukab624bc42015-09-29 19:13:55 -0700212 AuthScope scope{AuthScope::kNone};
213 if (dict->GetString(config_keys::kLocalAnonymousAccessRole, &tmp) &&
214 StringToEnum(tmp, &scope)) {
215 set_local_anonymous_access_role(scope);
216 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700217
218 if (dict->GetBoolean(config_keys::kLocalDiscoveryEnabled, &tmp_bool))
219 set_local_discovery_enabled(tmp_bool);
220
221 if (dict->GetBoolean(config_keys::kLocalPairingEnabled, &tmp_bool))
222 set_local_pairing_enabled(tmp_bool);
223
Vitaly Buka8589b052015-09-29 00:46:14 -0700224 if (dict->GetString(config_keys::kCloudId, &tmp))
225 set_cloud_id(tmp);
226
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700227 if (dict->GetString(config_keys::kDeviceId, &tmp))
228 set_device_id(tmp);
229
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700230 if (dict->GetString(config_keys::kRefreshToken, &tmp))
231 set_refresh_token(tmp);
232
233 if (dict->GetString(config_keys::kRobotAccount, &tmp))
234 set_robot_account(tmp);
235
236 if (dict->GetString(config_keys::kLastConfiguredSsid, &tmp))
237 set_last_configured_ssid(tmp);
238
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800239 std::vector<uint8_t> secret;
240 if (dict->GetString(config_keys::kSecret, &tmp) && Base64Decode(tmp, &secret))
241 set_secret(secret);
Vitaly Bukaa5803282015-12-06 20:11:55 -0800242
Vitaly Buka63c98622015-12-11 11:06:04 -0800243 RootClientTokenOwner token_owner{RootClientTokenOwner::kNone};
244 if (dict->GetString(config_keys::kRootClientTokenOwner, &tmp) &&
245 StringToEnum(tmp, &token_owner)) {
246 set_root_client_token_owner(token_owner);
247 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700248}
249
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700250void Config::Save() {
251 if (!config_store_)
252 return;
253
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700254 base::DictionaryValue dict;
Vitaly Bukabced5af2015-10-12 17:42:30 -0700255 dict.SetInteger(config_keys::kVersion, kCurrentConfigVersion);
256
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700257 dict.SetString(config_keys::kClientId, settings_.client_id);
258 dict.SetString(config_keys::kClientSecret, settings_.client_secret);
259 dict.SetString(config_keys::kApiKey, settings_.api_key);
Vitaly Buka1e019fa2016-02-10 11:28:16 -0800260 dict.SetString(config_keys::kOAuthUrl, settings_.oauth_url);
261 dict.SetString(config_keys::kServiceUrl, settings_.service_url);
Vitaly Buka3b8fbc52016-02-04 15:42:04 -0800262 dict.SetString(config_keys::kXmppEndpoint, settings_.xmpp_endpoint);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700263 dict.SetString(config_keys::kRefreshToken, settings_.refresh_token);
Johan Euphrosine312c2f52015-09-29 00:04:29 -0700264 dict.SetString(config_keys::kCloudId, settings_.cloud_id);
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700265 dict.SetString(config_keys::kDeviceId, settings_.device_id);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700266 dict.SetString(config_keys::kRobotAccount, settings_.robot_account);
267 dict.SetString(config_keys::kLastConfiguredSsid,
268 settings_.last_configured_ssid);
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800269 dict.SetString(config_keys::kSecret, Base64Encode(settings_.secret));
Vitaly Buka63c98622015-12-11 11:06:04 -0800270 dict.SetString(config_keys::kRootClientTokenOwner,
271 EnumToString(settings_.root_client_token_owner));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700272 dict.SetString(config_keys::kName, settings_.name);
273 dict.SetString(config_keys::kDescription, settings_.description);
274 dict.SetString(config_keys::kLocation, settings_.location);
275 dict.SetString(config_keys::kLocalAnonymousAccessRole,
Vitaly Bukab624bc42015-09-29 19:13:55 -0700276 EnumToString(settings_.local_anonymous_access_role));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700277 dict.SetBoolean(config_keys::kLocalDiscoveryEnabled,
278 settings_.local_discovery_enabled);
279 dict.SetBoolean(config_keys::kLocalPairingEnabled,
280 settings_.local_pairing_enabled);
281
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700282 std::string json_string;
283 base::JSONWriter::WriteWithOptions(
284 dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
285
Vitaly Bukaac18fcf2016-01-15 14:48:54 -0800286 config_store_->SaveSettings(
287 kConfigName, json_string,
288 base::Bind([](ErrorPtr error) { CHECK(!error); }));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700289}
290
291Config::Transaction::~Transaction() {
292 Commit();
293}
294
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700295void Config::Transaction::Commit() {
296 if (!config_)
297 return;
298 if (save_)
299 config_->Save();
300 for (const auto& cb : config_->on_changed_)
301 cb.Run(*settings_);
302 config_ = nullptr;
303}
304
305} // namespace weave