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