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
|
// 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/hash.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();
std::string filename =
base::HexEncode(crypto::hash::Sha256(serialized_origin));
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
|