1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
content / browser / lock_screen / lock_screen_storage_impl.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/lock_screen/lock_screen_storage_impl.h"
#include <map>
#include <memory>
#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/singleton.h"
#include "base/path_service.h"
#include "base/sequence_checker.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/values.h"
#include "components/value_store/value_store.h"
#include "components/value_store/value_store_factory.h"
#include "components/value_store/value_store_factory_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "crypto/sha2.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "url/origin.h"
using value_store::ValueStore;
namespace content {
namespace {
// See Extensions.Database.Open in histograms.xml.
const char kValueStoreDatabaseUMAClientName[] = "WebAppsLockScreen";
} // namespace
// Helper class for running blocking tasks on a thread pool.
class LockScreenStorageHelper {
public:
LockScreenStorageHelper();
~LockScreenStorageHelper() = default;
void Init(const base::FilePath& base_path);
std::vector<std::string> GetKeys(const url::Origin& origin);
bool SetData(const url::Origin& origin,
const std::string& key,
const std::string& data);
private:
ValueStore* GetValueStoreForOrigin(const url::Origin& origin);
scoped_refptr<value_store::ValueStoreFactory> value_store_factory_;
// Maps storage directory filename to ValueStore for a particular origin.
// TODO(crbug.com/40204655): If there can only be one lock screen app at a
// time, this does not need to be a map. Otherwise, there should be a clean
// way of evicting value stores databases from this cache.
std::map<std::string, std::unique_ptr<ValueStore>> storage_map_;
};
LockScreenStorageHelper::LockScreenStorageHelper() {}
void LockScreenStorageHelper::Init(const base::FilePath& base_path) {
value_store_factory_ =
base::MakeRefCounted<value_store::ValueStoreFactoryImpl>(base_path);
}
std::vector<std::string> LockScreenStorageHelper::GetKeys(
const url::Origin& origin) {
ValueStore* value_store = GetValueStoreForOrigin(origin);
ValueStore::ReadResult read = value_store->Get();
std::vector<std::string> result;
if (!read.status().ok())
return result;
for (auto kv : read.settings()) {
result.push_back(kv.first);
}
return result;
}
bool LockScreenStorageHelper::SetData(const url::Origin& origin,
const std::string& key,
const std::string& data) {
ValueStore* value_store = GetValueStoreForOrigin(origin);
ValueStore::WriteResult write =
value_store->Set(ValueStore::DEFAULTS, key, base::Value(data));
return write.status().ok();
}
ValueStore* LockScreenStorageHelper::GetValueStoreForOrigin(
const url::Origin& origin) {
DCHECK(!origin.opaque());
// ValueStore will create a directory for storing its data. The directory name
// is passed in. We want to key data by origin, so we use a hash of the origin
// as the directory name under which to store the data. Origin.Serialize()
// should just concatenate the scheme/host/port, which are the components that
// need to appear identical if the two origins need to compare equal. Hence
// if two origins are equal, the serialized origins should also be equal.
std::string serialized_origin = origin.Serialize();
uint8_t hash[crypto::kSHA256Length];
crypto::SHA256HashString(serialized_origin, hash, sizeof(hash));
std::string filename = base::HexEncode(hash);
auto iter = storage_map_.find(filename);
if (iter != storage_map_.end())
return iter->second.get();
base::FilePath value_store_path(filename);
std::unique_ptr<ValueStore> value_store =
value_store_factory_->CreateValueStore(value_store_path,
kValueStoreDatabaseUMAClientName);
ValueStore* result = value_store.get();
storage_map_.emplace(filename, std::move(value_store));
return result;
}
// static
LockScreenStorage* LockScreenStorage::GetInstance() {
return LockScreenStorageImpl::GetInstance();
}
// static
LockScreenStorageImpl* LockScreenStorageImpl::GetInstance() {
return base::Singleton<
LockScreenStorageImpl,
base::LeakySingletonTraits<LockScreenStorageImpl>>::get();
}
LockScreenStorageImpl::LockScreenStorageImpl()
: helper_(base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})) {
}
LockScreenStorageImpl::~LockScreenStorageImpl() = default;
void LockScreenStorageImpl::Init(content::BrowserContext* browser_context,
const base::FilePath& base_path) {
DCHECK(!browser_context_);
DCHECK(!browser_context->IsOffTheRecord());
browser_context_ = browser_context;
helper_.AsyncCall(&LockScreenStorageHelper::Init).WithArgs(base_path);
}
void LockScreenStorageImpl::GetKeys(
const url::Origin& origin,
blink::mojom::LockScreenService::GetKeysCallback callback) {
helper_.AsyncCall(&LockScreenStorageHelper::GetKeys)
.WithArgs(origin)
.Then(base::BindOnce(&LockScreenStorageImpl::OnGetKeys,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void LockScreenStorageImpl::SetData(
const url::Origin& origin,
const std::string& key,
const std::string& data,
blink::mojom::LockScreenService::SetDataCallback callback) {
helper_.AsyncCall(&LockScreenStorageHelper::SetData)
.WithArgs(origin, key, data)
.Then(base::BindOnce(&LockScreenStorageImpl::OnSetData,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
bool LockScreenStorageImpl::IsAllowedBrowserContext(
content::BrowserContext* browser_context) {
return browser_context == browser_context_;
}
void LockScreenStorageImpl::OnGetKeys(
blink::mojom::LockScreenService::GetKeysCallback callback,
const std::vector<std::string>& result) {
std::move(callback).Run(result);
}
void LockScreenStorageImpl::OnSetData(
blink::mojom::LockScreenService::SetDataCallback callback,
bool success) {
if (success) {
std::move(callback).Run(blink::mojom::LockScreenServiceStatus::kSuccess);
} else {
std::move(callback).Run(blink::mojom::LockScreenServiceStatus::kWriteError);
}
}
void LockScreenStorageImpl::InitForTesting(
content::BrowserContext* browser_context,
const base::FilePath& base_path) {
browser_context_ = nullptr;
Init(browser_context, base_path);
}
} // namespace content