blob: fe50e3bc30192b79d0085d612abfbb17045b70fc [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
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020018#include "src/privet/privet_types.h"
19#include "src/string_utils.h"
Vitaly Bukad322a3c2015-08-16 01:03:02 -070020
Vitaly Bukad322a3c2015-08-16 01:03:02 -070021namespace weave {
22
23namespace config_keys {
24
Vitaly Bukabced5af2015-10-12 17:42:30 -070025const char kVersion[] = "version";
26
Vitaly Bukad322a3c2015-08-16 01:03:02 -070027const char kClientId[] = "client_id";
28const char kClientSecret[] = "client_secret";
29const char kApiKey[] = "api_key";
30const char kOAuthURL[] = "oauth_url";
31const char kServiceURL[] = "service_url";
32const char kName[] = "name";
33const char kDescription[] = "description";
34const char kLocation[] = "location";
35const char kLocalAnonymousAccessRole[] = "local_anonymous_access_role";
36const char kLocalDiscoveryEnabled[] = "local_discovery_enabled";
37const char kLocalPairingEnabled[] = "local_pairing_enabled";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070038const char kRefreshToken[] = "refresh_token";
Johan Euphrosine312c2f52015-09-29 00:04:29 -070039const char kCloudId[] = "cloud_id";
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070040const char kDeviceId[] = "device_id";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070041const char kRobotAccount[] = "robot_account";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070042const char kLastConfiguredSsid[] = "last_configured_ssid";
Vitaly Buka8589b052015-09-29 00:46:14 -070043const char kSecret[] = "secret";
Vitaly Bukad322a3c2015-08-16 01:03:02 -070044
45} // namespace config_keys
46
Vitaly Buka0d7aac82015-11-16 23:02:24 -080047const char kWeaveUrl[] = "https://www.googleapis.com/weave/v1/";
48const char kDeprecatedUrl[] = "https://www.googleapis.com/clouddevices/v1/";
49
Vitaly Bukac11a17d2015-08-15 10:36:10 -070050namespace {
51
Vitaly Bukabced5af2015-10-12 17:42:30 -070052const int kCurrentConfigVersion = 1;
53
54void MigrateFromV0(base::DictionaryValue* dict) {
55 std::string cloud_id;
56 if (dict->GetString(config_keys::kCloudId, &cloud_id) && !cloud_id.empty())
57 return;
58 scoped_ptr<base::Value> tmp;
59 if (dict->Remove(config_keys::kDeviceId, &tmp))
60 dict->Set(config_keys::kCloudId, std::move(tmp));
61}
62
Vitaly Buka238db692015-09-29 16:58:39 -070063Config::Settings CreateDefaultSettings() {
64 Config::Settings result;
Vitaly Bukad322a3c2015-08-16 01:03:02 -070065 result.oauth_url = "https://accounts.google.com/o/oauth2/";
Vitaly Buka0d7aac82015-11-16 23:02:24 -080066 result.service_url = kWeaveUrl;
Vitaly Bukab624bc42015-09-29 19:13:55 -070067 result.local_anonymous_access_role = AuthScope::kViewer;
Vitaly Buka52d006a2015-11-21 17:14:51 -080068 result.pairing_modes.insert(PairingType::kPinCode);
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -070069 result.device_id = base::GenerateGUID();
Vitaly Bukad322a3c2015-08-16 01:03:02 -070070 return result;
71}
72
Vitaly Bukac11a17d2015-08-15 10:36:10 -070073} // namespace
Vitaly Bukad322a3c2015-08-16 01:03:02 -070074
Vitaly Buka1e363672015-09-25 14:01:16 -070075Config::Config(provider::ConfigStore* config_store)
Vitaly Bukac11a17d2015-08-15 10:36:10 -070076 : settings_{CreateDefaultSettings()}, config_store_{config_store} {
Vitaly Bukac11a17d2015-08-15 10:36:10 -070077}
Vitaly Bukad322a3c2015-08-16 01:03:02 -070078
79void Config::AddOnChangedCallback(const OnChangedCallback& callback) {
80 on_changed_.push_back(callback);
81 // Force to read current state.
82 callback.Run(settings_);
83}
84
Vitaly Buka238db692015-09-29 16:58:39 -070085const Config::Settings& Config::GetSettings() const {
Vitaly Bukad322a3c2015-08-16 01:03:02 -070086 return settings_;
87}
88
Vitaly Bukac11a17d2015-08-15 10:36:10 -070089void Config::Load() {
Vitaly Bukad322a3c2015-08-16 01:03:02 -070090 Transaction change{this};
91 change.save_ = false;
92
Vitaly Bukac11a17d2015-08-15 10:36:10 -070093 settings_ = CreateDefaultSettings();
94
95 if (!config_store_)
96 return;
97
98 // Crash on any mistakes in defaults.
99 CHECK(config_store_->LoadDefaults(&settings_));
100
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700101 CHECK(!settings_.client_id.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700102 CHECK(!settings_.client_secret.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700103 CHECK(!settings_.api_key.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700104 CHECK(!settings_.oauth_url.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700105 CHECK(!settings_.service_url.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700106 CHECK(!settings_.oem_name.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700107 CHECK(!settings_.model_name.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700108 CHECK(!settings_.model_id.empty());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700109 CHECK(!settings_.name.empty());
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700110 CHECK(!settings_.device_id.empty());
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700111 CHECK_EQ(
112 settings_.embedded_code.empty(),
113 std::find(settings_.pairing_modes.begin(), settings_.pairing_modes.end(),
114 PairingType::kEmbeddedCode) == settings_.pairing_modes.end());
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700115
Vitaly Buka8589b052015-09-29 00:46:14 -0700116 // Values below will be generated at runtime.
117 CHECK(settings_.cloud_id.empty());
118 CHECK(settings_.refresh_token.empty());
119 CHECK(settings_.robot_account.empty());
120 CHECK(settings_.last_configured_ssid.empty());
121 CHECK(settings_.secret.empty());
122
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700123 change.LoadState();
124}
125
126void Config::Transaction::LoadState() {
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700127 if (!config_->config_store_)
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700128 return;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700129 std::string json_string = config_->config_store_->LoadSettings();
130 if (json_string.empty())
131 return;
132
133 auto value = base::JSONReader::Read(json_string);
Vitaly Bukabced5af2015-10-12 17:42:30 -0700134 base::DictionaryValue* dict = nullptr;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700135 if (!value || !value->GetAsDictionary(&dict)) {
136 LOG(ERROR) << "Failed to parse settings.";
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700137 return;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700138 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700139
Vitaly Bukabced5af2015-10-12 17:42:30 -0700140 int loaded_version = 0;
141 dict->GetInteger(config_keys::kVersion, &loaded_version);
142
143 if (loaded_version != kCurrentConfigVersion) {
144 LOG(INFO) << "State version mismatch. expected: " << kCurrentConfigVersion
145 << ", loaded: " << loaded_version;
146 save_ = true;
147 }
148
149 if (loaded_version == 0) {
150 MigrateFromV0(dict);
151 }
152
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700153 std::string tmp;
154 bool tmp_bool{false};
155
156 if (dict->GetString(config_keys::kClientId, &tmp))
157 set_client_id(tmp);
158
159 if (dict->GetString(config_keys::kClientSecret, &tmp))
160 set_client_secret(tmp);
161
162 if (dict->GetString(config_keys::kApiKey, &tmp))
163 set_api_key(tmp);
164
165 if (dict->GetString(config_keys::kOAuthURL, &tmp))
166 set_oauth_url(tmp);
167
Vitaly Buka0d7aac82015-11-16 23:02:24 -0800168 if (dict->GetString(config_keys::kServiceURL, &tmp)) {
169 if (tmp == kDeprecatedUrl)
170 tmp = kWeaveUrl;
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700171 set_service_url(tmp);
Vitaly Buka0d7aac82015-11-16 23:02:24 -0800172 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700173
174 if (dict->GetString(config_keys::kName, &tmp))
175 set_name(tmp);
176
177 if (dict->GetString(config_keys::kDescription, &tmp))
178 set_description(tmp);
179
180 if (dict->GetString(config_keys::kLocation, &tmp))
181 set_location(tmp);
182
Vitaly Bukab624bc42015-09-29 19:13:55 -0700183 AuthScope scope{AuthScope::kNone};
184 if (dict->GetString(config_keys::kLocalAnonymousAccessRole, &tmp) &&
185 StringToEnum(tmp, &scope)) {
186 set_local_anonymous_access_role(scope);
187 }
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700188
189 if (dict->GetBoolean(config_keys::kLocalDiscoveryEnabled, &tmp_bool))
190 set_local_discovery_enabled(tmp_bool);
191
192 if (dict->GetBoolean(config_keys::kLocalPairingEnabled, &tmp_bool))
193 set_local_pairing_enabled(tmp_bool);
194
Vitaly Buka8589b052015-09-29 00:46:14 -0700195 if (dict->GetString(config_keys::kCloudId, &tmp))
196 set_cloud_id(tmp);
197
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700198 if (dict->GetString(config_keys::kDeviceId, &tmp))
199 set_device_id(tmp);
200
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700201 if (dict->GetString(config_keys::kRefreshToken, &tmp))
202 set_refresh_token(tmp);
203
204 if (dict->GetString(config_keys::kRobotAccount, &tmp))
205 set_robot_account(tmp);
206
207 if (dict->GetString(config_keys::kLastConfiguredSsid, &tmp))
208 set_last_configured_ssid(tmp);
209
Vitaly Buka8589b052015-09-29 00:46:14 -0700210 if (dict->GetString(config_keys::kSecret, &tmp))
211 set_secret(tmp);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700212}
213
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700214void Config::Save() {
215 if (!config_store_)
216 return;
217
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700218 base::DictionaryValue dict;
Vitaly Bukabced5af2015-10-12 17:42:30 -0700219 dict.SetInteger(config_keys::kVersion, kCurrentConfigVersion);
220
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700221 dict.SetString(config_keys::kClientId, settings_.client_id);
222 dict.SetString(config_keys::kClientSecret, settings_.client_secret);
223 dict.SetString(config_keys::kApiKey, settings_.api_key);
224 dict.SetString(config_keys::kOAuthURL, settings_.oauth_url);
225 dict.SetString(config_keys::kServiceURL, settings_.service_url);
226 dict.SetString(config_keys::kRefreshToken, settings_.refresh_token);
Johan Euphrosine312c2f52015-09-29 00:04:29 -0700227 dict.SetString(config_keys::kCloudId, settings_.cloud_id);
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700228 dict.SetString(config_keys::kDeviceId, settings_.device_id);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700229 dict.SetString(config_keys::kRobotAccount, settings_.robot_account);
230 dict.SetString(config_keys::kLastConfiguredSsid,
231 settings_.last_configured_ssid);
Vitaly Buka8589b052015-09-29 00:46:14 -0700232 dict.SetString(config_keys::kSecret, settings_.secret);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700233 dict.SetString(config_keys::kName, settings_.name);
234 dict.SetString(config_keys::kDescription, settings_.description);
235 dict.SetString(config_keys::kLocation, settings_.location);
236 dict.SetString(config_keys::kLocalAnonymousAccessRole,
Vitaly Bukab624bc42015-09-29 19:13:55 -0700237 EnumToString(settings_.local_anonymous_access_role));
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700238 dict.SetBoolean(config_keys::kLocalDiscoveryEnabled,
239 settings_.local_discovery_enabled);
240 dict.SetBoolean(config_keys::kLocalPairingEnabled,
241 settings_.local_pairing_enabled);
242
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700243 std::string json_string;
244 base::JSONWriter::WriteWithOptions(
245 dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
246
247 config_store_->SaveSettings(json_string);
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700248}
249
250Config::Transaction::~Transaction() {
251 Commit();
252}
253
Vitaly Bukad322a3c2015-08-16 01:03:02 -0700254void Config::Transaction::Commit() {
255 if (!config_)
256 return;
257 if (save_)
258 config_->Save();
259 for (const auto& cb : config_->on_changed_)
260 cb.Run(*settings_);
261 config_ = nullptr;
262}
263
264} // namespace weave