1 //
2 // Copyright (C) 2015 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "shill/json_store.h"
18
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <cinttypes>
25 #include <map>
26 #include <memory>
27 #include <typeinfo>
28 #include <vector>
29
30 #include <base/files/important_file_writer.h>
31 #include <base/files/file_util.h>
32 #include <base/json/json_string_value_serializer.h>
33 #include <base/memory/scoped_ptr.h>
34 #include <base/strings/string_number_conversions.h>
35 #include <base/strings/string_util.h>
36 #include <base/strings/stringprintf.h>
37 #include <base/values.h>
38
39 #include "shill/crypto_rot47.h"
40 #include "shill/logging.h"
41 #include "shill/scoped_umask.h"
42
43 using std::map;
44 using std::set;
45 using std::string;
46 using std::unique_ptr;
47 using std::vector;
48
49 namespace shill {
50
51 namespace Logging {
52
53 static auto kModuleLogScope = ScopeLogger::kStorage;
ObjectID(const JsonStore * j)54 static string ObjectID(const JsonStore* j) {
55 return "(unknown)";
56 }
57
58 } // namespace Logging
59
60 namespace {
61
62 static const char kCorruptSuffix[] = ".corrupted";
63 static const char kCoercedValuePropertyEncodedValue[] = "_encoded_value";
64 static const char kCoercedValuePropertyNativeType[] = "_native_type";
65 static const char kNativeTypeNonAsciiString[] = "non_ascii_string";
66 static const char kNativeTypeUint64[] = "uint64";
67 static const char kRootPropertyDescription[] = "description";
68 static const char kRootPropertySettings[] = "settings";
69
DoesGroupContainProperties(const brillo::VariantDictionary & group,const brillo::VariantDictionary & required_properties)70 bool DoesGroupContainProperties(
71 const brillo::VariantDictionary& group,
72 const brillo::VariantDictionary& required_properties) {
73 for (const auto& required_property_name_and_value : required_properties) {
74 const auto& required_key = required_property_name_and_value.first;
75 const auto& required_value = required_property_name_and_value.second;
76 const auto& group_it = group.find(required_key);
77 if (group_it == group.end() || group_it->second != required_value) {
78 return false;
79 }
80 }
81 return true;
82 }
83
84 // Deserialization helpers.
85
86 // A coerced value is used to represent values that base::Value does
87 // not directly support. A coerced value has the form
88 // {'_native_type': <type-as-string>, '_encoded_value': <value-as-string>}
IsCoercedValue(const base::DictionaryValue & value)89 bool IsCoercedValue(const base::DictionaryValue& value) {
90 return value.HasKey(kCoercedValuePropertyNativeType) &&
91 value.HasKey(kCoercedValuePropertyEncodedValue);
92 }
93
DecodeCoercedValue(const base::DictionaryValue & coerced_value)94 unique_ptr<brillo::Any> DecodeCoercedValue(
95 const base::DictionaryValue& coerced_value) {
96 string native_type;
97 if (!coerced_value.GetStringWithoutPathExpansion(
98 kCoercedValuePropertyNativeType, &native_type)) {
99 LOG(ERROR) << "Property |" << kCoercedValuePropertyNativeType
100 << "| is not a string.";
101 return nullptr;
102 }
103
104 string encoded_value;
105 if (!coerced_value.GetStringWithoutPathExpansion(
106 kCoercedValuePropertyEncodedValue, &encoded_value)) {
107 LOG(ERROR) << "Property |" << kCoercedValuePropertyEncodedValue
108 << "| is not a string.";
109 return nullptr;
110 }
111
112 if (native_type == kNativeTypeNonAsciiString) {
113 vector<uint8_t> native_value;
114 if (base::HexStringToBytes(encoded_value, &native_value)) {
115 return unique_ptr<brillo::Any>(
116 new brillo::Any(string(native_value.begin(), native_value.end())));
117 } else {
118 LOG(ERROR) << "Failed to decode hex data from |" << encoded_value << "|.";
119 return nullptr;
120 }
121 } else if (native_type == kNativeTypeUint64) {
122 uint64_t native_value;
123 if (base::StringToUint64(encoded_value, &native_value)) {
124 return unique_ptr<brillo::Any>(new brillo::Any(native_value));
125 } else {
126 LOG(ERROR) << "Failed to parse uint64 from |" << encoded_value << "|.";
127 return nullptr;
128 }
129 } else {
130 LOG(ERROR) << "Unsupported native type |" << native_type << "|.";
131 return nullptr;
132 }
133 }
134
MakeStringFromValue(const base::Value & value)135 unique_ptr<string> MakeStringFromValue(const base::Value& value) {
136 const auto value_type = value.GetType();
137
138 if (value_type == base::Value::TYPE_STRING) {
139 unique_ptr<string> unwrapped_string(new string());
140 value.GetAsString(unwrapped_string.get());
141 return unwrapped_string;
142 } else if (value_type == base::Value::TYPE_DICTIONARY) {
143 const base::DictionaryValue* dictionary_value;
144 value.GetAsDictionary(&dictionary_value);
145 unique_ptr<brillo::Any> decoded_value(
146 DecodeCoercedValue(*dictionary_value));
147 if (!decoded_value) {
148 LOG(ERROR) << "Failed to decode coerced value.";
149 return nullptr;
150 }
151
152 if (!decoded_value->IsTypeCompatible<string>()) {
153 LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<string>()
154 << "| from |" << decoded_value->GetUndecoratedTypeName()
155 << ".";
156 return nullptr;
157 }
158 return unique_ptr<string>(new string(decoded_value->Get<string>()));
159 } else {
160 LOG(ERROR) << "Got unexpected type |" << value_type << "|.";
161 return nullptr;
162 }
163 }
164
ConvertListValueToStringVector(const base::ListValue & list_value)165 unique_ptr<vector<string>> ConvertListValueToStringVector(
166 const base::ListValue& list_value) {
167 const size_t list_len = list_value.GetSize();
168 for (size_t i = 0; i < list_len; ++i) {
169 const base::Value* list_item;
170 list_value.Get(i, &list_item);
171 const auto item_type = list_item->GetType();
172 if (item_type != base::Value::TYPE_STRING &&
173 item_type != base::Value::TYPE_DICTIONARY) {
174 LOG(ERROR) << "Element " << i << " has type " << item_type << ", "
175 << "instead of expected types "
176 << base::Value::TYPE_STRING << " or "
177 << base::Value::TYPE_DICTIONARY << ".";
178 return nullptr;
179 }
180 }
181
182 unique_ptr<vector<string>> result(new vector<string>);
183 for (size_t i = 0; i < list_len; ++i) {
184 const base::Value* list_item;
185 unique_ptr<string> native_string;
186 list_value.Get(i, &list_item);
187 native_string = MakeStringFromValue(*list_item);
188 if (!native_string) {
189 LOG(ERROR) << "Failed to parse string from element " << i << ".";
190 return nullptr;
191 }
192 result->push_back(*native_string);
193 }
194 return result;
195 }
196
197 unique_ptr<brillo::VariantDictionary>
ConvertDictionaryValueToVariantDictionary(const base::DictionaryValue & dictionary_value)198 ConvertDictionaryValueToVariantDictionary(
199 const base::DictionaryValue& dictionary_value) {
200 base::DictionaryValue::Iterator it(dictionary_value);
201 unique_ptr<brillo::VariantDictionary> variant_dictionary(
202 new brillo::VariantDictionary());
203 while (!it.IsAtEnd()) {
204 const string& key = it.key();
205 const base::Value& value = it.value();
206 switch (value.GetType()) {
207 case base::Value::TYPE_NULL:
208 LOG(ERROR) << "Key |" << key << "| has unsupported TYPE_NULL.";
209 return nullptr;
210 case base::Value::TYPE_BOOLEAN: {
211 bool native_bool;
212 value.GetAsBoolean(&native_bool);
213 (*variant_dictionary)[key] = native_bool;
214 break;
215 }
216 case base::Value::TYPE_INTEGER: {
217 int native_int;
218 value.GetAsInteger(&native_int);
219 (*variant_dictionary)[key] = native_int;
220 break;
221 }
222 case base::Value::TYPE_DOUBLE:
223 LOG(ERROR) << "Key |" << key << "| has unsupported TYPE_DOUBLE.";
224 return nullptr;
225 case base::Value::TYPE_STRING: {
226 string native_string;
227 value.GetAsString(&native_string);
228 (*variant_dictionary)[key] = native_string;
229 break;
230 }
231 case base::Value::TYPE_BINARY:
232 /* The JSON parser should never create Values of this type. */
233 LOG(ERROR) << "Key |" << key << "| has unexpected TYPE_BINARY.";
234 return nullptr;
235 case base::Value::TYPE_DICTIONARY: {
236 const base::DictionaryValue* dictionary_value;
237 value.GetAsDictionary(&dictionary_value);
238 if (!IsCoercedValue(*dictionary_value)) {
239 LOG(ERROR) << "Key |" << key << "| has unsupported TYPE_DICTIONARY.";
240 return nullptr;
241 }
242 unique_ptr<brillo::Any> decoded_coerced_value(
243 DecodeCoercedValue(*dictionary_value));
244 if (!decoded_coerced_value) {
245 LOG(ERROR) << "Key |" << key << "| could not be decoded.";
246 return nullptr;
247 }
248 (*variant_dictionary)[key] = *decoded_coerced_value;
249 break;
250 }
251 case base::Value::TYPE_LIST: { // Only string lists, for now.
252 const base::ListValue* list_value;
253 value.GetAsList(&list_value);
254
255 unique_ptr<vector<string>> string_list(
256 ConvertListValueToStringVector(*list_value));
257 if (!string_list) {
258 LOG(ERROR) << "Key |" << key << "| could not be decoded.";
259 return nullptr;
260 }
261 (*variant_dictionary)[key] = *string_list;
262 break;
263 }
264 }
265 it.Advance();
266 }
267 return variant_dictionary;
268 }
269
270 // Serialization helpers.
271
MakeCoercedValue(const string & native_type,const string & encoded_value)272 scoped_ptr<base::DictionaryValue> MakeCoercedValue(
273 const string& native_type, const string& encoded_value) {
274 auto coerced_value(make_scoped_ptr(new base::DictionaryValue()));
275 coerced_value->SetStringWithoutPathExpansion(
276 kCoercedValuePropertyNativeType, native_type);
277 coerced_value->SetStringWithoutPathExpansion(
278 kCoercedValuePropertyEncodedValue, encoded_value);
279 return coerced_value;
280 }
281
MakeValueForString(const string & native_string)282 scoped_ptr<base::Value> MakeValueForString(const string& native_string) {
283 // Strictly speaking, we don't need to escape non-ASCII text, if
284 // that text is UTF-8. Practically speaking, however, it'll be
285 // easier to inspect config files if all non-ASCII strings are
286 // presented as byte sequences. (Unicode has many code points with
287 // similar-looking glyphs.)
288 if (base::IsStringASCII(native_string) &&
289 native_string.find('\0') == string::npos) {
290 return make_scoped_ptr(new base::StringValue(native_string));
291 } else {
292 const string hex_encoded_string(
293 base::HexEncode(native_string.data(), native_string.size()));
294 return MakeCoercedValue(kNativeTypeNonAsciiString, hex_encoded_string);
295 }
296 }
297
ConvertVariantDictionaryToDictionaryValue(const brillo::VariantDictionary & variant_dictionary)298 scoped_ptr<base::DictionaryValue> ConvertVariantDictionaryToDictionaryValue(
299 const brillo::VariantDictionary& variant_dictionary) {
300 auto dictionary_value(make_scoped_ptr(new base::DictionaryValue()));
301 for (const auto& key_and_value : variant_dictionary) {
302 const auto& key = key_and_value.first;
303 const auto& value = key_and_value.second;
304 if (value.IsTypeCompatible<bool>()) {
305 dictionary_value->SetBooleanWithoutPathExpansion(key, value.Get<bool>());
306 } else if (value.IsTypeCompatible<int32_t>()) {
307 dictionary_value->SetIntegerWithoutPathExpansion(key, value.Get<int>());
308 } else if (value.IsTypeCompatible<string>()) {
309 dictionary_value->SetWithoutPathExpansion(
310 key, MakeValueForString(value.Get<string>()));
311 } else if (value.IsTypeCompatible<uint64_t>()) {
312 const string encoded_value(
313 base::StringPrintf("%" PRIu64, value.Get<uint64_t>()));
314 dictionary_value->SetWithoutPathExpansion(
315 key, MakeCoercedValue(kNativeTypeUint64, encoded_value));
316 } else if (value.IsTypeCompatible<vector<string>>()) {
317 auto list_value(make_scoped_ptr(new base::ListValue()));
318 for (const auto& string_list_item : value.Get<vector<string>>()) {
319 list_value->Append(MakeValueForString(string_list_item));
320 }
321 dictionary_value->SetWithoutPathExpansion(key, std::move(list_value));
322 } else {
323 LOG(ERROR) << "Failed to convert element with key |" << key << "|.";
324 return nullptr;
325 }
326 }
327 return dictionary_value;
328 }
329
330 } // namespace
331
JsonStore(const base::FilePath & path)332 JsonStore::JsonStore(const base::FilePath& path)
333 : path_(path) {
334 CHECK(!path_.empty());
335 }
336
IsNonEmpty() const337 bool JsonStore::IsNonEmpty() const {
338 int64_t file_size = 0;
339 return base::GetFileSize(path_, &file_size) && file_size != 0;
340 }
341
Open()342 bool JsonStore::Open() {
343 if (!IsNonEmpty()) {
344 LOG(INFO) << "Creating a new key file at |" << path_.value() << "|.";
345 return true;
346 }
347
348 string json_string;
349 if (!base::ReadFileToString(path_, &json_string)) {
350 LOG(ERROR) << "Failed to read data from |" << path_.value() << "|.";
351 return false;
352 }
353
354 JSONStringValueDeserializer json_deserializer(json_string);
355 unique_ptr<base::Value> json_value;
356 string json_error;
357 json_deserializer.set_allow_trailing_comma(true);
358 json_value.reset(
359 json_deserializer.Deserialize(nullptr, &json_error).release());
360 if (!json_value) {
361 LOG(ERROR) << "Failed to parse JSON data from |" << path_.value() <<"|.";
362 SLOG(this, 5) << json_error;
363 return false;
364 }
365
366 const base::DictionaryValue* root_dictionary;
367 if (!json_value->GetAsDictionary(&root_dictionary)) {
368 LOG(ERROR) << "JSON value is not a dictionary.";
369 return false;
370 }
371
372 CHECK(root_dictionary);
373 if (root_dictionary->HasKey(kRootPropertyDescription) &&
374 !root_dictionary->GetStringWithoutPathExpansion(
375 kRootPropertyDescription, &file_description_)) {
376 LOG(WARNING) << "Property |" << kRootPropertyDescription
377 << "| is not a string.";
378 // Description is non-critical, so continue processing.
379 }
380
381 if (!root_dictionary->HasKey(kRootPropertySettings)) {
382 LOG(ERROR) << "Property |" << kRootPropertySettings << "| is missing.";
383 return false;
384 }
385
386 const base::DictionaryValue* settings_dictionary;
387 if (!root_dictionary->GetDictionaryWithoutPathExpansion(
388 kRootPropertySettings, &settings_dictionary)) {
389 LOG(ERROR) << "Property |" << kRootPropertySettings
390 << "| is not a dictionary.";
391 return false;
392 }
393
394 if (!group_name_to_settings_.empty()) {
395 LOG(INFO) << "Clearing existing settings on open.";
396 group_name_to_settings_.clear();
397 }
398
399 base::DictionaryValue::Iterator it(*settings_dictionary);
400 while (!it.IsAtEnd()) {
401 const string& group_name = it.key();
402 const base::DictionaryValue* group_settings_as_values;
403 if (!it.value().GetAsDictionary(&group_settings_as_values)) {
404 LOG(ERROR) << "Group |" << group_name << "| is not a dictionary.";
405 return false;
406 }
407
408 unique_ptr<brillo::VariantDictionary> group_settings_as_variants =
409 ConvertDictionaryValueToVariantDictionary(*group_settings_as_values);
410 if (!group_settings_as_variants) {
411 LOG(ERROR) << "Failed to convert group |" << group_name
412 << "| to variants.";
413 return false;
414 }
415
416 group_name_to_settings_[group_name] = *group_settings_as_variants;
417 it.Advance();
418 }
419
420 return true;
421 }
422
Close()423 bool JsonStore::Close() {
424 return Flush();
425 }
426
Flush()427 bool JsonStore::Flush() {
428 auto groups(make_scoped_ptr(new base::DictionaryValue()));
429 for (const auto& group_name_and_settings : group_name_to_settings_) {
430 const auto& group_name = group_name_and_settings.first;
431 scoped_ptr<base::DictionaryValue> group_settings(
432 ConvertVariantDictionaryToDictionaryValue(
433 group_name_and_settings.second));
434 if (!group_settings) {
435 // This class maintains the invariant that anything placed in
436 // |group_settings| is convertible. So abort if conversion fails.
437 LOG(FATAL) << "Failed to convert group |" << group_name << "|.";
438 return false;
439 }
440 groups->SetWithoutPathExpansion(group_name, std::move(group_settings));
441 }
442
443 base::DictionaryValue root;
444 root.SetStringWithoutPathExpansion(
445 kRootPropertyDescription, file_description_);
446 root.SetWithoutPathExpansion(kRootPropertySettings, std::move(groups));
447
448 string json_string;
449 JSONStringValueSerializer json_serializer(&json_string);
450 json_serializer.set_pretty_print(true);
451 if (!json_serializer.Serialize(root)) {
452 LOG(ERROR) << "Failed to serialize to JSON.";
453 return false;
454 }
455
456 ScopedUmask owner_only_umask(~(S_IRUSR | S_IWUSR) & 0777);
457 if (!base::ImportantFileWriter::WriteFileAtomically(path_, json_string)) {
458 LOG(ERROR) << "Failed to write JSON file: |" << path_.value() << "|.";
459 return false;
460 }
461
462 return true;
463 }
464
MarkAsCorrupted()465 bool JsonStore::MarkAsCorrupted() {
466 LOG(INFO) << "In " << __func__ << " for " << path_.value();
467 string corrupted_path = path_.value() + kCorruptSuffix;
468 int ret = rename(path_.value().c_str(), corrupted_path.c_str());
469 if (ret != 0) {
470 PLOG(ERROR) << "File rename failed.";
471 return false;
472 }
473 return true;
474 }
475
GetGroups() const476 set<string> JsonStore::GetGroups() const {
477 set<string> matching_groups;
478 for (const auto& group_name_and_settings : group_name_to_settings_) {
479 matching_groups.insert(group_name_and_settings.first);
480 }
481 return matching_groups;
482 }
483
484 // Returns a set so that caller can easily test whether a particular group
485 // is contained within this collection.
GetGroupsWithKey(const string & key) const486 set<string> JsonStore::GetGroupsWithKey(const string& key) const {
487 set<string> matching_groups;
488 // iterate over groups, find ones with matching key
489 for (const auto& group_name_and_settings : group_name_to_settings_) {
490 const auto& group_name = group_name_and_settings.first;
491 const auto& group_settings = group_name_and_settings.second;
492 if (group_settings.find(key) != group_settings.end()) {
493 matching_groups.insert(group_name);
494 }
495 }
496 return matching_groups;
497 }
498
GetGroupsWithProperties(const KeyValueStore & properties) const499 set<string> JsonStore::GetGroupsWithProperties(const KeyValueStore& properties)
500 const {
501 set<string> matching_groups;
502 const brillo::VariantDictionary& properties_dict(properties.properties());
503 for (const auto& group_name_and_settings : group_name_to_settings_) {
504 const auto& group_name = group_name_and_settings.first;
505 const auto& group_settings = group_name_and_settings.second;
506 if (DoesGroupContainProperties(group_settings, properties_dict)) {
507 matching_groups.insert(group_name);
508 }
509 }
510 return matching_groups;
511 }
512
ContainsGroup(const string & group) const513 bool JsonStore::ContainsGroup(const string& group) const {
514 const auto& it = group_name_to_settings_.find(group);
515 return it != group_name_to_settings_.end();
516 }
517
DeleteKey(const string & group,const string & key)518 bool JsonStore::DeleteKey(const string& group, const string& key) {
519 const auto& group_name_and_settings = group_name_to_settings_.find(group);
520 if (group_name_and_settings == group_name_to_settings_.end()) {
521 LOG(ERROR) << "Could not find group |" << group << "|.";
522 return false;
523 }
524
525 auto& group_settings = group_name_and_settings->second;
526 auto property_it = group_settings.find(key);
527 if (property_it != group_settings.end()) {
528 group_settings.erase(property_it);
529 }
530
531 return true;
532 }
533
DeleteGroup(const string & group)534 bool JsonStore::DeleteGroup(const string& group) {
535 auto group_name_and_settings = group_name_to_settings_.find(group);
536 if (group_name_and_settings != group_name_to_settings_.end()) {
537 group_name_to_settings_.erase(group_name_and_settings);
538 }
539 return true;
540 }
541
SetHeader(const string & header)542 bool JsonStore::SetHeader(const string& header) {
543 file_description_ = header;
544 return true;
545 }
546
GetString(const string & group,const string & key,string * value) const547 bool JsonStore::GetString(const string& group,
548 const string& key,
549 string* value) const {
550 return ReadSetting(group, key, value);
551 }
552
SetString(const string & group,const string & key,const string & value)553 bool JsonStore::SetString(
554 const string& group, const string& key, const string& value) {
555 return WriteSetting(group, key, value);
556 }
557
GetBool(const string & group,const string & key,bool * value) const558 bool JsonStore::GetBool(const string& group, const string& key, bool* value)
559 const {
560 return ReadSetting(group, key, value);
561 }
562
SetBool(const string & group,const string & key,bool value)563 bool JsonStore::SetBool(const string& group, const string& key, bool value) {
564 return WriteSetting(group, key, value);
565 }
566
GetInt(const string & group,const string & key,int * value) const567 bool JsonStore::GetInt(
568 const string& group, const string& key, int* value) const {
569 return ReadSetting(group, key, value);
570 }
571
SetInt(const string & group,const string & key,int value)572 bool JsonStore::SetInt(const string& group, const string& key, int value) {
573 return WriteSetting(group, key, value);
574 }
575
GetUint64(const string & group,const string & key,uint64_t * value) const576 bool JsonStore::GetUint64(
577 const string& group, const string& key, uint64_t* value) const {
578 return ReadSetting(group, key, value);
579 }
580
SetUint64(const string & group,const string & key,uint64_t value)581 bool JsonStore::SetUint64(
582 const string& group, const string& key, uint64_t value) {
583 return WriteSetting(group, key, value);
584 }
585
GetStringList(const string & group,const string & key,vector<string> * value) const586 bool JsonStore::GetStringList(
587 const string& group, const string& key, vector<string>* value) const {
588 return ReadSetting(group, key, value);
589 }
590
SetStringList(const string & group,const string & key,const vector<string> & value)591 bool JsonStore::SetStringList(
592 const string& group, const string& key, const vector<string>& value) {
593 return WriteSetting(group, key, value);
594 }
595
GetCryptedString(const string & group,const string & key,string * value)596 bool JsonStore::GetCryptedString(
597 const string& group, const string& key, string* value) {
598 string encrypted_value;
599 if (!GetString(group, key, &encrypted_value)) {
600 return false;
601 }
602
603 // TODO(quiche): Once we've removed the glib dependency in
604 // CryptoProvider, move to using CryptoProvider, instead of
605 // CryptoROT47 directly. This change should be done before using
606 // JsonStore in production, as the on-disk format of crypted strings
607 // will change.
608 CryptoROT47 rot47;
609 string decrypted_value;
610 if (!rot47.Decrypt(encrypted_value, &decrypted_value)) {
611 LOG(ERROR) << "Failed to decrypt value for |" << group << "|"
612 << ":|" << key << "|.";
613 return false;
614 }
615
616 if (value) {
617 *value = decrypted_value;
618 }
619 return true;
620 }
621
SetCryptedString(const string & group,const string & key,const string & value)622 bool JsonStore::SetCryptedString(
623 const string& group, const string& key, const string& value) {
624 CryptoROT47 rot47;
625 string encrypted_value;
626 if (!rot47.Encrypt(value, &encrypted_value)) {
627 LOG(ERROR) << "Failed to encrypt value for |" << group << "|"
628 << ":|" << key << "|.";
629 return false;
630 }
631
632 return SetString(group, key, encrypted_value);
633 }
634
635 // Private methods.
636 template<typename T>
ReadSetting(const string & group,const string & key,T * out) const637 bool JsonStore::ReadSetting(
638 const string& group, const string& key, T* out) const {
639 const auto& group_name_and_settings = group_name_to_settings_.find(group);
640 if (group_name_and_settings == group_name_to_settings_.end()) {
641 SLOG(this, 10) << "Could not find group |" << group << "|.";
642 return false;
643 }
644
645 const auto& group_settings = group_name_and_settings->second;
646 const auto& property_name_and_value = group_settings.find(key);
647 if (property_name_and_value == group_settings.end()) {
648 SLOG(this, 10) << "Could not find property |" << key << "|.";
649 return false;
650 }
651
652 if (!property_name_and_value->second.IsTypeCompatible<T>()) {
653 // We assume that the reader and the writer agree on the exact
654 // type. So we do not allow implicit conversion.
655 LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<T>()
656 << "| from |"
657 << property_name_and_value->second.GetUndecoratedTypeName()
658 << "|.";
659 return false;
660 }
661
662 if (out) {
663 return property_name_and_value->second.GetValue(out);
664 } else {
665 return true;
666 }
667 }
668
669 template<typename T>
WriteSetting(const string & group,const string & key,const T & new_value)670 bool JsonStore::WriteSetting(
671 const string& group, const string& key, const T& new_value) {
672 auto group_name_and_settings = group_name_to_settings_.find(group);
673 if (group_name_and_settings == group_name_to_settings_.end()) {
674 group_name_to_settings_[group][key] = new_value;
675 return true;
676 }
677
678 auto& group_settings = group_name_and_settings->second;
679 auto property_name_and_value = group_settings.find(key);
680 if (property_name_and_value == group_settings.end()) {
681 group_settings[key] = new_value;
682 return true;
683 }
684
685 if (!property_name_and_value->second.IsTypeCompatible<T>()) {
686 SLOG(this, 10) << "New type |" << brillo::GetUndecoratedTypeName<T>()
687 << "| differs from current type |"
688 << property_name_and_value->second.GetUndecoratedTypeName()
689 << "|.";
690 return false;
691 } else {
692 property_name_and_value->second = new_value;
693 return true;
694 }
695 }
696
697 } // namespace shill
698