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.
5 #include "chrome/browser/safe_browsing/incident_reporting/state_store.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/values.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
12 #include "chrome/common/pref_names.h"
14 namespace safe_browsing
{
16 // StateStore::Transaction -----------------------------------------------------
18 StateStore::Transaction::Transaction(StateStore
* store
) : store_(store
) {
20 DCHECK(!store_
->has_transaction_
);
21 store_
->has_transaction_
= true;
25 StateStore::Transaction::~Transaction() {
27 store_
->has_transaction_
= false;
31 void StateStore::Transaction::MarkAsReported(IncidentType type
,
32 const std::string
& key
,
33 IncidentDigest digest
) {
34 std::string
type_string(base::IntToString(static_cast<int32_t>(type
)));
35 base::DictionaryValue
* incidents_sent
= GetPrefDict();
36 base::DictionaryValue
* type_dict
= nullptr;
37 if (!incidents_sent
->GetDictionaryWithoutPathExpansion(type_string
,
39 type_dict
= new base::DictionaryValue();
40 incidents_sent
->SetWithoutPathExpansion(type_string
, type_dict
);
42 type_dict
->SetStringWithoutPathExpansion(key
, base::UintToString(digest
));
45 void StateStore::Transaction::ClearForType(IncidentType type
) {
46 // Nothing to do if the pref dict does not exist.
47 if (!store_
->incidents_sent_
)
50 // Use the read-only view on the preference to figure out if there is a value
51 // to remove before committing to making a change since any use of GetPrefDict
52 // will result in a full serialize-and-write operation on the preferences
54 std::string
type_string(base::IntToString(static_cast<int32_t>(type
)));
55 const base::DictionaryValue
* type_dict
= nullptr;
56 if (store_
->incidents_sent_
->GetDictionaryWithoutPathExpansion(type_string
,
58 GetPrefDict()->RemoveWithoutPathExpansion(type_string
, nullptr);
62 base::DictionaryValue
* StateStore::Transaction::GetPrefDict() {
64 pref_update_
.reset(new DictionaryPrefUpdate(
65 store_
->profile_
->GetPrefs(), prefs::kSafeBrowsingIncidentsSent
));
66 // Getting the dict will cause it to be created if it doesn't exist.
67 // Unconditionally refresh the store's read-only view on the preference so
68 // that it will always be correct.
69 store_
->incidents_sent_
= pref_update_
->Get();
71 return pref_update_
->Get();
75 // StateStore ------------------------------------------------------------------
77 StateStore::StateStore(Profile
* profile
)
79 incidents_sent_(nullptr)
82 has_transaction_(false)
85 // Cache a read-only view of the preference.
86 const base::Value
* value
=
87 profile_
->GetPrefs()->GetUserPrefValue(prefs::kSafeBrowsingIncidentsSent
);
89 value
->GetAsDictionary(&incidents_sent_
);
91 Transaction
transaction(this);
92 CleanLegacyValues(&transaction
);
95 StateStore::~StateStore() {
97 DCHECK(!has_transaction_
);
101 bool StateStore::HasBeenReported(IncidentType type
,
102 const std::string
& key
,
103 IncidentDigest digest
) {
104 const base::DictionaryValue
* type_dict
= nullptr;
105 std::string digest_string
;
106 return (incidents_sent_
&&
107 incidents_sent_
->GetDictionaryWithoutPathExpansion(
108 base::IntToString(static_cast<int32_t>(type
)), &type_dict
) &&
109 type_dict
->GetStringWithoutPathExpansion(key
, &digest_string
) &&
110 digest_string
== base::UintToString(digest
));
113 void StateStore::CleanLegacyValues(Transaction
* transaction
) {
114 static const IncidentType kLegacyTypes
[] = {
115 // TODO(grt): remove in M44 (crbug.com/451173).
116 IncidentType::OMNIBOX_INTERACTION
,
119 for (IncidentType type
: kLegacyTypes
)
120 transaction
->ClearForType(type
);
123 } // namespace safe_browsing