xref: /aosp_15_r20/external/cronet/components/metrics/structured/key_data_prefs_delegate.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/metrics/structured/key_data_prefs_delegate.h"
6 
7 #include <optional>
8 #include <utility>
9 
10 #include "base/check.h"
11 #include "base/logging.h"
12 #include "base/values.h"
13 #include "components/metrics/structured/lib/key_data.h"
14 #include "components/metrics/structured/lib/key_util.h"
15 #include "components/metrics/structured/lib/proto/key.pb.h"
16 #include "components/metrics/structured/project_validator.h"
17 #include "components/metrics/structured/structured_metrics_validator.h"
18 #include "components/prefs/scoped_user_pref_update.h"
19 
20 namespace metrics::structured {
21 
KeyDataPrefsDelegate(PrefService * local_state,std::string_view pref_name)22 KeyDataPrefsDelegate::KeyDataPrefsDelegate(PrefService* local_state,
23                                            std::string_view pref_name)
24     : local_state_(local_state), pref_name_(pref_name) {
25   CHECK(local_state_);
26   CHECK(!pref_name_.empty());
27 
28   LoadKeysFromPrefs();
29 }
30 
31 KeyDataPrefsDelegate::~KeyDataPrefsDelegate() = default;
32 
IsReady() const33 bool KeyDataPrefsDelegate::IsReady() const {
34   return true;
35 }
36 
GetKey(uint64_t project_name_hash) const37 const KeyProto* KeyDataPrefsDelegate::GetKey(uint64_t project_name_hash) const {
38   CHECK(IsReady());
39   auto it = proto_.keys().find(project_name_hash);
40   if (it != proto_.keys().end()) {
41     return &it->second;
42   }
43   return nullptr;
44 }
45 
UpsertKey(uint64_t project_name_hash,base::TimeDelta last_key_rotation,base::TimeDelta key_rotation_period)46 void KeyDataPrefsDelegate::UpsertKey(uint64_t project_name_hash,
47                                      base::TimeDelta last_key_rotation,
48                                      base::TimeDelta key_rotation_period) {
49   KeyProto& key_proto = (*(proto_.mutable_keys()))[project_name_hash];
50   key_proto.set_key(util::GenerateNewKey());
51   key_proto.set_last_rotation(last_key_rotation.InDays());
52   key_proto.set_rotation_period(key_rotation_period.InDays());
53 
54   UpdatePrefsByProject(project_name_hash, key_proto);
55 }
56 
Purge()57 void KeyDataPrefsDelegate::Purge() {
58   // Clears in-memory keys.
59   proto_.mutable_keys()->clear();
60 
61   // Clears persisted keys.
62   local_state_->ClearPref(pref_name_);
63 }
64 
LoadKeysFromPrefs()65 void KeyDataPrefsDelegate::LoadKeysFromPrefs() {
66   const base::Value::Dict& keys_pref = local_state_->GetDict(pref_name_);
67 
68   // Use the validators to get the project name to project hash mapping.
69   const validator::Validators* validators = validator::Validators::Get();
70 
71   auto* proto_keys = proto_.mutable_keys();
72 
73   for (const auto [project_name, project_keys] : keys_pref) {
74     std::optional<const ProjectValidator*> project_validator =
75         validators->GetProjectValidator(project_name);
76 
77     // Check if a project was found for the name.
78     if (!project_validator.has_value()) {
79       continue;
80     }
81 
82     const uint64_t project_hash = (*project_validator)->project_hash();
83     const base::Value::Dict* value_dict = project_keys.GetIfDict();
84     if (!value_dict) {
85       LOG(ERROR) << "Key Pref value was expected to be a dict.";
86       continue;
87     }
88 
89     std::optional<KeyProto> key_data =
90         util::CreateKeyProtoFromValue(*value_dict);
91 
92     if (!key_data.has_value()) {
93       LOG(ERROR) << "Failed to convert pref value into key data.";
94       continue;
95     }
96 
97     (*proto_keys)[project_hash] = *key_data;
98   }
99 }
100 
UpdatePrefsByProject(uint64_t project_name_hash,const KeyProto & key_proto)101 void KeyDataPrefsDelegate::UpdatePrefsByProject(uint64_t project_name_hash,
102                                                 const KeyProto& key_proto) {
103   ScopedDictPrefUpdate pref_updater(local_state_, pref_name_);
104 
105   base::Value::Dict& dict = pref_updater.Get();
106 
107   // Get the name of the project for |project_name_hash| to be used to store the
108   // keys in prefs.
109   const validator::Validators* validators = validator::Validators::Get();
110   std::optional<base::StringPiece> project_name =
111       validators->GetProjectName(project_name_hash);
112 
113   if (!project_name.has_value()) {
114     LOG(ERROR) << "Attempting to store key for invalid project: "
115                << project_name_hash;
116     return;
117   }
118 
119   dict.Set(*project_name, util::CreateValueFromKeyProto(key_proto));
120 }
121 
122 }  // namespace metrics::structured
123