• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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