#include "components/cookie_config/cookie_store_util.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "build/build_config.h"
#include "components/os_crypt/async/browser/os_crypt_async.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "net/extras/sqlite/cookie_crypto_delegate.h"
namespace cookie_config {
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ARKWEB)
namespace {
void OnOsCryptReadyOnUi(
base::OnceCallback<void(os_crypt_async::Encryptor)> callback,
scoped_refptr<base::SequencedTaskRunner> task_runner,
os_crypt_async::Encryptor encryptor) {
task_runner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(encryptor)));
}
void InitOnUi(base::OnceCallback<void(os_crypt_async::Encryptor)> callback,
os_crypt_async::OSCryptAsync* os_crypt_async,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
os_crypt_async->GetInstance(
base::BindOnce(&OnOsCryptReadyOnUi, std::move(callback),
std::move(task_runner)),
os_crypt_async::Encryptor::Option::kEncryptSyncCompat);
}
class CookieOSCryptoDelegate : public net::CookieCryptoDelegate {
public:
CookieOSCryptoDelegate(
os_crypt_async::OSCryptAsync* os_crypt_async,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
CookieOSCryptoDelegate(const CookieOSCryptoDelegate&) = delete;
CookieOSCryptoDelegate& operator=(const CookieOSCryptoDelegate&) = delete;
~CookieOSCryptoDelegate() override;
void Init(base::OnceClosure callback) override;
bool EncryptString(const std::string& plaintext,
std::string* ciphertext) override;
bool DecryptString(const std::string& ciphertext,
std::string* plaintext) override;
private:
void OnOsCryptReady(os_crypt_async::Encryptor encryptor);
raw_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
std::optional<os_crypt_async::Encryptor> encryptor_;
bool initializing_ = false;
std::vector<base::OnceClosure> init_callbacks_;
base::WeakPtrFactory<CookieOSCryptoDelegate> weak_ptr_factory_{this};
};
CookieOSCryptoDelegate::CookieOSCryptoDelegate(
os_crypt_async::OSCryptAsync* os_crypt_async,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
: os_crypt_async_(os_crypt_async), ui_task_runner_(ui_task_runner) {}
CookieOSCryptoDelegate::~CookieOSCryptoDelegate() = default;
void CookieOSCryptoDelegate::Init(base::OnceClosure callback) {
if (encryptor_.has_value()) {
std::move(callback).Run();
return;
}
init_callbacks_.emplace_back(std::move(callback));
if (initializing_) {
return;
}
initializing_ = true;
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&InitOnUi,
base::BindOnce(&CookieOSCryptoDelegate::OnOsCryptReady,
weak_ptr_factory_.GetWeakPtr()),
os_crypt_async_,
base::SequencedTaskRunner::GetCurrentDefault()));
os_crypt_async_ = nullptr;
}
bool CookieOSCryptoDelegate::EncryptString(const std::string& plaintext,
std::string* ciphertext) {
CHECK(encryptor_) << "EncryptString called before Init completed";
return encryptor_->EncryptString(plaintext, ciphertext);
}
bool CookieOSCryptoDelegate::DecryptString(const std::string& ciphertext,
std::string* plaintext) {
CHECK(encryptor_) << "DecryptString called before Init completed";
return encryptor_->DecryptString(ciphertext, plaintext);
}
void CookieOSCryptoDelegate::OnOsCryptReady(
os_crypt_async::Encryptor encryptor) {
encryptor_ = std::move(encryptor);
initializing_ = false;
for (auto& callback : init_callbacks_) {
std::move(callback).Run();
}
init_callbacks_.clear();
}
}
std::unique_ptr<net::CookieCryptoDelegate> GetCookieCryptoDelegate(
os_crypt_async::OSCryptAsync* os_crypt_async,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
return std::make_unique<CookieOSCryptoDelegate>(os_crypt_async,
ui_task_runner);
}
#else
std::unique_ptr<net::CookieCryptoDelegate> GetCookieCryptoDelegate(
os_crypt_async::OSCryptAsync* os_crypt_async,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
return nullptr;
}
#endif
}