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/browser/safe_browsing/incident_reporting/platform_state_store.h"
13 #include "chrome/common/pref_names.h"
15 namespace safe_browsing
{
17 // StateStore::Transaction -----------------------------------------------------
19 StateStore::Transaction::Transaction(StateStore
* store
) : store_(store
) {
21 DCHECK(!store_
->has_transaction_
);
22 store_
->has_transaction_
= true;
26 StateStore::Transaction::~Transaction() {
28 store_
->has_transaction_
= false;
31 platform_state_store::Store(store_
->profile_
, store_
->incidents_sent_
);
34 void StateStore::Transaction::MarkAsReported(IncidentType type
,
35 const std::string
& key
,
36 IncidentDigest digest
) {
37 std::string
type_string(base::IntToString(static_cast<int32_t>(type
)));
38 base::DictionaryValue
* incidents_sent
= GetPrefDict();
39 base::DictionaryValue
* type_dict
= nullptr;
40 if (!incidents_sent
->GetDictionaryWithoutPathExpansion(type_string
,
42 type_dict
= new base::DictionaryValue();
43 incidents_sent
->SetWithoutPathExpansion(type_string
, type_dict
);
45 type_dict
->SetStringWithoutPathExpansion(key
, base::UintToString(digest
));
48 void StateStore::Transaction::ClearForType(IncidentType type
) {
49 // Nothing to do if the pref dict does not exist.
50 if (!store_
->incidents_sent_
)
53 // Use the read-only view on the preference to figure out if there is a value
54 // to remove before committing to making a change since any use of GetPrefDict
55 // will result in a full serialize-and-write operation on the preferences
57 std::string
type_string(base::IntToString(static_cast<int32_t>(type
)));
58 const base::DictionaryValue
* type_dict
= nullptr;
59 if (store_
->incidents_sent_
->GetDictionaryWithoutPathExpansion(type_string
,
61 GetPrefDict()->RemoveWithoutPathExpansion(type_string
, nullptr);
65 void StateStore::Transaction::ClearAll() {
68 if (store_
->incidents_sent_
) {
69 store_
->incidents_sent_
= nullptr;
70 store_
->profile_
->GetPrefs()->ClearPref(prefs::kSafeBrowsingIncidentsSent
);
74 base::DictionaryValue
* StateStore::Transaction::GetPrefDict() {
76 pref_update_
.reset(new DictionaryPrefUpdate(
77 store_
->profile_
->GetPrefs(), prefs::kSafeBrowsingIncidentsSent
));
78 // Getting the dict will cause it to be created if it doesn't exist.
79 // Unconditionally refresh the store's read-only view on the preference so
80 // that it will always be correct.
81 store_
->incidents_sent_
= pref_update_
->Get();
83 return pref_update_
->Get();
86 void StateStore::Transaction::ReplacePrefDict(
87 scoped_ptr
<base::DictionaryValue
> pref_dict
) {
88 GetPrefDict()->Swap(pref_dict
.get());
92 // StateStore ------------------------------------------------------------------
94 StateStore::StateStore(Profile
* profile
)
96 incidents_sent_(nullptr)
99 has_transaction_(false)
102 // Cache a read-only view of the preference.
103 const base::Value
* value
=
104 profile_
->GetPrefs()->GetUserPrefValue(prefs::kSafeBrowsingIncidentsSent
);
106 value
->GetAsDictionary(&incidents_sent_
);
108 // Apply the platform data.
109 Transaction
transaction(this);
110 scoped_ptr
<base::DictionaryValue
> value_dict(
111 platform_state_store::Load(profile_
));
113 if (value_dict
->empty())
114 transaction
.ClearAll();
115 else if (!incidents_sent_
|| !incidents_sent_
->Equals(value_dict
.get()))
116 transaction
.ReplacePrefDict(value_dict
.Pass());
120 CleanLegacyValues(&transaction
);
123 StateStore::~StateStore() {
125 DCHECK(!has_transaction_
);
129 bool StateStore::HasBeenReported(IncidentType type
,
130 const std::string
& key
,
131 IncidentDigest digest
) {
132 const base::DictionaryValue
* type_dict
= nullptr;
133 std::string digest_string
;
134 return (incidents_sent_
&&
135 incidents_sent_
->GetDictionaryWithoutPathExpansion(
136 base::IntToString(static_cast<int32_t>(type
)), &type_dict
) &&
137 type_dict
->GetStringWithoutPathExpansion(key
, &digest_string
) &&
138 digest_string
== base::UintToString(digest
));
141 void StateStore::CleanLegacyValues(Transaction
* transaction
) {
142 static const IncidentType kLegacyTypes
[] = {
143 // TODO(grt): remove in M44 (crbug.com/451173).
144 IncidentType::OMNIBOX_INTERACTION
,
147 for (IncidentType type
: kLegacyTypes
)
148 transaction
->ClearForType(type
);
151 } // namespace safe_browsing