OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // This file implements the platform-neutral Load() and Store() functions for a |
| 6 // profile's safebrowsing.incidents_sent preference dictionary. The preference |
| 7 // dict is converted to a protocol buffer message which is then serialized into |
| 8 // a byte array. This serialized data is written to or read from some |
| 9 // platform-specific storage via {Read,Write}StoreData implemented elsewhere. |
| 10 // |
| 11 // A pref dict like so: |
| 12 // { "0": {"key1": "1235"}, {"key2": "6789"}}} |
| 13 // is converted to an identical protocol buffer message, where the top-level |
| 14 // mapping's keys are of type int, and the nested mappings' values are of type |
| 15 // uint32_t. |
| 16 |
| 17 #include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h
" |
| 18 |
| 19 #include "base/values.h" |
| 20 |
| 21 #if defined(USE_PLATFORM_STATE_STORE) |
| 22 |
| 23 #include "base/metrics/histogram_macros.h" |
| 24 #include "base/strings/string_number_conversions.h" |
| 25 #include "chrome/browser/safe_browsing/incident_reporting/state_store_data.pb.h" |
| 26 #include "third_party/protobuf/src/google/protobuf/repeated_field.h" |
| 27 |
| 28 #endif // USE_PLATFORM_STATE_STORE |
| 29 |
| 30 namespace safe_browsing { |
| 31 namespace platform_state_store { |
| 32 |
| 33 #if defined(USE_PLATFORM_STATE_STORE) |
| 34 |
| 35 namespace { |
| 36 |
| 37 using google::protobuf::RepeatedPtrField; |
| 38 |
| 39 // Copies the (key, digest) pairs from |keys_and_digests| (a dict of string |
| 40 // values) to the |key_digest_pairs| protobuf. |
| 41 void KeysAndDigestsToProtobuf( |
| 42 const base::DictionaryValue& keys_and_digests, |
| 43 RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>* |
| 44 key_digest_pairs) { |
| 45 for (base::DictionaryValue::Iterator iter(keys_and_digests); !iter.IsAtEnd(); |
| 46 iter.Advance()) { |
| 47 const base::StringValue* digest_value = nullptr; |
| 48 if (!iter.value().GetAsString(&digest_value)) { |
| 49 NOTREACHED(); |
| 50 continue; |
| 51 } |
| 52 uint32_t digest = 0; |
| 53 if (!base::StringToUint(digest_value->GetString(), &digest)) { |
| 54 NOTREACHED(); |
| 55 continue; |
| 56 } |
| 57 StateStoreData::Incidents::KeyDigestMapFieldEntry* key_digest = |
| 58 key_digest_pairs->Add(); |
| 59 key_digest->set_key(iter.key()); |
| 60 key_digest->set_digest(digest); |
| 61 } |
| 62 } |
| 63 |
| 64 // Copies the (type, dict) pairs from |incidents_sent| (a dict of dict values) |
| 65 // to the |typed_incidents| protobuf. |
| 66 void IncidentsSentToProtobuf( |
| 67 const base::DictionaryValue& incidents_sent, |
| 68 RepeatedPtrField<StateStoreData::TypeIncidentsMapFieldEntry>* |
| 69 type_incidents_pairs) { |
| 70 for (base::DictionaryValue::Iterator iter(incidents_sent); !iter.IsAtEnd(); |
| 71 iter.Advance()) { |
| 72 const base::DictionaryValue* keys_and_digests = nullptr; |
| 73 if (!iter.value().GetAsDictionary(&keys_and_digests)) { |
| 74 NOTREACHED(); |
| 75 continue; |
| 76 } |
| 77 if (keys_and_digests->empty()) |
| 78 continue; |
| 79 int incident_type = 0; |
| 80 if (!base::StringToInt(iter.key(), &incident_type)) { |
| 81 NOTREACHED(); |
| 82 continue; |
| 83 } |
| 84 StateStoreData::TypeIncidentsMapFieldEntry* entry = |
| 85 type_incidents_pairs->Add(); |
| 86 entry->set_type(incident_type); |
| 87 KeysAndDigestsToProtobuf( |
| 88 *keys_and_digests, entry->mutable_incidents()->mutable_key_to_digest()); |
| 89 } |
| 90 } |
| 91 |
| 92 // Copies the (key, digest) pairs for a specific incident type into |type_dict| |
| 93 // (a dict of string values). |
| 94 void RestoreOfTypeFromProtobuf( |
| 95 const RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>& |
| 96 key_digest_pairs, |
| 97 base::DictionaryValue* type_dict) { |
| 98 for (const auto& key_digest : key_digest_pairs) { |
| 99 if (!key_digest.has_key() || !key_digest.has_digest()) |
| 100 continue; |
| 101 type_dict->SetStringWithoutPathExpansion( |
| 102 key_digest.key(), base::UintToString(key_digest.digest())); |
| 103 } |
| 104 } |
| 105 |
| 106 // Copies the (type, dict) pairs into |value_dict| (a dict of dict values). |
| 107 void RestoreFromProtobuf( |
| 108 const RepeatedPtrField<StateStoreData::TypeIncidentsMapFieldEntry>& |
| 109 type_incidents_pairs, |
| 110 base::DictionaryValue* value_dict) { |
| 111 for (const auto& type_incidents : type_incidents_pairs) { |
| 112 if (!type_incidents.has_type() || !type_incidents.has_incidents() || |
| 113 type_incidents.incidents().key_to_digest_size() == 0) { |
| 114 continue; |
| 115 } |
| 116 std::string type_string(base::IntToString(type_incidents.type())); |
| 117 base::DictionaryValue* type_dict = nullptr; |
| 118 if (!value_dict->GetDictionaryWithoutPathExpansion(type_string, |
| 119 &type_dict)) { |
| 120 type_dict = new base::DictionaryValue(); |
| 121 value_dict->SetWithoutPathExpansion(type_string, type_dict); |
| 122 } |
| 123 RestoreOfTypeFromProtobuf(type_incidents.incidents().key_to_digest(), |
| 124 type_dict); |
| 125 } |
| 126 } |
| 127 |
| 128 } // namespace |
| 129 |
| 130 #endif // USE_PLATFORM_STATE_STORE |
| 131 |
| 132 scoped_ptr<base::DictionaryValue> Load(Profile* profile) { |
| 133 #if defined(USE_PLATFORM_STATE_STORE) |
| 134 scoped_ptr<base::DictionaryValue> value_dict(new base::DictionaryValue()); |
| 135 std::string data; |
| 136 PlatformStateStoreLoadResult result = ReadStoreData(profile, &data); |
| 137 if (result == PlatformStateStoreLoadResult::SUCCESS) |
| 138 result = DeserializeIncidentsSent(data, value_dict.get()); |
| 139 switch (result) { |
| 140 case PlatformStateStoreLoadResult::SUCCESS: |
| 141 case PlatformStateStoreLoadResult::CLEARED_DATA: |
| 142 case PlatformStateStoreLoadResult::CLEARED_NO_DATA: |
| 143 // Return a (possibly empty) dictionary for the success cases. |
| 144 break; |
| 145 case PlatformStateStoreLoadResult::DATA_CLEAR_FAILED: |
| 146 case PlatformStateStoreLoadResult::OPEN_FAILED: |
| 147 case PlatformStateStoreLoadResult::READ_FAILED: |
| 148 case PlatformStateStoreLoadResult::PARSE_ERROR: |
| 149 // Return null for all error cases. |
| 150 value_dict.reset(); |
| 151 break; |
| 152 } |
| 153 UMA_HISTOGRAM_ENUMERATION( |
| 154 "SBIRS.PSSLoadResult", static_cast<uint32_t>(result), |
| 155 static_cast<uint32_t>(PlatformStateStoreLoadResult::NUM_RESULTS)); |
| 156 return value_dict.Pass(); |
| 157 #else |
| 158 return scoped_ptr<base::DictionaryValue>(); |
| 159 #endif |
| 160 } |
| 161 |
| 162 void Store(Profile* profile, const base::DictionaryValue* incidents_sent) { |
| 163 #if defined(USE_PLATFORM_STATE_STORE) |
| 164 std::string data; |
| 165 SerializeIncidentsSent(incidents_sent, &data); |
| 166 UMA_HISTOGRAM_COUNTS("SBIRS.PSSDataStoreSize", data.size()); |
| 167 WriteStoreData(profile, data); |
| 168 #endif |
| 169 } |
| 170 |
| 171 #if defined(USE_PLATFORM_STATE_STORE) |
| 172 |
| 173 void SerializeIncidentsSent(const base::DictionaryValue* incidents_sent, |
| 174 std::string* data) { |
| 175 StateStoreData store_data; |
| 176 |
| 177 IncidentsSentToProtobuf(*incidents_sent, |
| 178 store_data.mutable_type_to_incidents()); |
| 179 store_data.SerializeToString(data); |
| 180 } |
| 181 |
| 182 PlatformStateStoreLoadResult DeserializeIncidentsSent( |
| 183 const std::string& data, |
| 184 base::DictionaryValue* value_dict) { |
| 185 StateStoreData store_data; |
| 186 if (data.empty()) { |
| 187 value_dict->Clear(); |
| 188 return PlatformStateStoreLoadResult::SUCCESS; |
| 189 } |
| 190 if (!store_data.ParseFromString(data)) |
| 191 return PlatformStateStoreLoadResult::PARSE_ERROR; |
| 192 value_dict->Clear(); |
| 193 RestoreFromProtobuf(store_data.type_to_incidents(), value_dict); |
| 194 return PlatformStateStoreLoadResult::SUCCESS; |
| 195 } |
| 196 |
| 197 #endif // USE_PLATFORM_STATE_STORE |
| 198 |
| 199 } // namespace platform_state_store |
| 200 } // namespace safe_browsing |
OLD | NEW |