mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
feat: introduce os_crypt_async in safeStorage (#49054)
* feat: support Freedesktop Secret Service OSCrypt client Refs https://issues.chromium.org/issues/40086962 Refs https://issues.chromium.org/issues/447372315 * chore: rework to async interface * refactor: allow customizing freedesktop config * docs: add more async impl info * refactor: reject when temporarily unavailable * chore: feedback from review * chore: push_back => emplace_back
This commit is contained in:
@@ -4,13 +4,19 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "shell/browser/api/electron_api_safe_storage.h"
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "components/os_crypt/async/browser/os_crypt_async.h"
|
||||
#include "components/os_crypt/sync/os_crypt.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/browser_process_impl.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/common/gin_converters/base_converter.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/handle.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/node_util.h"
|
||||
|
||||
@@ -18,17 +24,130 @@ namespace {
|
||||
|
||||
const char* kEncryptionVersionPrefixV10 = "v10";
|
||||
const char* kEncryptionVersionPrefixV11 = "v11";
|
||||
bool use_password_v10 = false;
|
||||
|
||||
bool IsEncryptionAvailable() {
|
||||
} // namespace
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
gin::DeprecatedWrapperInfo SafeStorage::kWrapperInfo = {
|
||||
gin::kEmbedderNativeGin};
|
||||
|
||||
SafeStorage::PendingEncrypt::PendingEncrypt(
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise,
|
||||
std::string plaintext)
|
||||
: promise(std::move(promise)), plaintext(std::move(plaintext)) {}
|
||||
SafeStorage::PendingEncrypt::~PendingEncrypt() = default;
|
||||
SafeStorage::PendingEncrypt::PendingEncrypt(PendingEncrypt&&) = default;
|
||||
SafeStorage::PendingEncrypt& SafeStorage::PendingEncrypt::operator=(
|
||||
PendingEncrypt&&) = default;
|
||||
|
||||
SafeStorage::PendingDecrypt::PendingDecrypt(
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise,
|
||||
std::string ciphertext)
|
||||
: promise(std::move(promise)), ciphertext(std::move(ciphertext)) {}
|
||||
SafeStorage::PendingDecrypt::~PendingDecrypt() = default;
|
||||
SafeStorage::PendingDecrypt::PendingDecrypt(PendingDecrypt&&) = default;
|
||||
SafeStorage::PendingDecrypt& SafeStorage::PendingDecrypt::operator=(
|
||||
PendingDecrypt&&) = default;
|
||||
|
||||
gin_helper::Handle<SafeStorage> SafeStorage::Create(v8::Isolate* isolate) {
|
||||
return gin_helper::CreateHandle(isolate, new SafeStorage(isolate));
|
||||
}
|
||||
|
||||
SafeStorage::SafeStorage(v8::Isolate* isolate) {
|
||||
if (electron::Browser::Get()->is_ready()) {
|
||||
OnFinishLaunching({});
|
||||
} else {
|
||||
Browser::Get()->AddObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
SafeStorage::~SafeStorage() {
|
||||
Browser::Get()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
gin::ObjectTemplateBuilder SafeStorage::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return gin_helper::DeprecatedWrappable<SafeStorage>::GetObjectTemplateBuilder(
|
||||
isolate)
|
||||
.SetMethod("isEncryptionAvailable", &SafeStorage::IsEncryptionAvailable)
|
||||
.SetMethod("isAsyncEncryptionAvailable",
|
||||
&SafeStorage::IsAsyncEncryptionAvailable)
|
||||
.SetMethod("setUsePlainTextEncryption", &SafeStorage::SetUsePasswordV10)
|
||||
.SetMethod("encryptString", &SafeStorage::EncryptString)
|
||||
.SetMethod("decryptString", &SafeStorage::DecryptString)
|
||||
.SetMethod("encryptStringAsync", &SafeStorage::encryptStringAsync)
|
||||
.SetMethod("decryptStringAsync", &SafeStorage::decryptStringAsync)
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
// Calling IsEncryptionAvailable() before the app is ready results in a crash
|
||||
// on Linux.
|
||||
// Refs: https://github.com/electron/electron/issues/32206.
|
||||
.SetMethod("getSelectedStorageBackend",
|
||||
&SafeStorage::GetSelectedLinuxBackend)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void SafeStorage::OnFinishLaunching(base::DictValue launch_info) {
|
||||
g_browser_process->os_crypt_async()->GetInstance(
|
||||
base::BindOnce(&SafeStorage::OnOsCryptReady, base::Unretained(this)),
|
||||
os_crypt_async::Encryptor::Option::kEncryptSyncCompat);
|
||||
}
|
||||
|
||||
void SafeStorage::OnOsCryptReady(os_crypt_async::Encryptor encryptor) {
|
||||
encryptor_ = std::move(encryptor);
|
||||
is_available_ = true;
|
||||
|
||||
for (auto& pending : pending_encrypts_) {
|
||||
std::string ciphertext;
|
||||
bool encrypted = encryptor_->EncryptString(pending.plaintext, &ciphertext);
|
||||
if (encrypted) {
|
||||
pending.promise.Resolve(
|
||||
electron::Buffer::Copy(pending.promise.isolate(), ciphertext)
|
||||
.ToLocalChecked());
|
||||
} else {
|
||||
pending.promise.RejectWithErrorMessage(
|
||||
"Error while encrypting the text provided to "
|
||||
"safeStorage.encryptStringAsync.");
|
||||
}
|
||||
}
|
||||
pending_encrypts_.clear();
|
||||
|
||||
for (auto& pending : pending_decrypts_) {
|
||||
std::string plaintext;
|
||||
os_crypt_async::Encryptor::DecryptFlags flags;
|
||||
bool decrypted =
|
||||
encryptor_->DecryptString(pending.ciphertext, &plaintext, &flags);
|
||||
|
||||
if (decrypted) {
|
||||
v8::Isolate* isolate = pending.promise.isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
|
||||
dict.Set("shouldReEncrypt", flags.should_reencrypt);
|
||||
dict.Set("result", plaintext);
|
||||
|
||||
pending.promise.Resolve(dict);
|
||||
} else if (flags.temporarily_unavailable) {
|
||||
pending.promise.RejectWithErrorMessage(
|
||||
"safeStorage.decryptStringAsync is temporarily unavailable. "
|
||||
"Please try again.");
|
||||
} else {
|
||||
pending.promise.RejectWithErrorMessage(
|
||||
"Error while decrypting the ciphertext provided to "
|
||||
"safeStorage.decryptStringAsync.");
|
||||
}
|
||||
}
|
||||
pending_decrypts_.clear();
|
||||
}
|
||||
|
||||
const char* SafeStorage::GetTypeName() {
|
||||
return "SafeStorage";
|
||||
}
|
||||
|
||||
bool SafeStorage::IsEncryptionAvailable() {
|
||||
if (!electron::Browser::Get()->is_ready())
|
||||
return false;
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
return OSCrypt::IsEncryptionAvailable() ||
|
||||
(use_password_v10 &&
|
||||
(use_password_v10_ &&
|
||||
static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
->linux_storage_backend() == "basic_text");
|
||||
#else
|
||||
@@ -36,12 +155,24 @@ bool IsEncryptionAvailable() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetUsePasswordV10(bool use) {
|
||||
use_password_v10 = use;
|
||||
bool SafeStorage::IsAsyncEncryptionAvailable() {
|
||||
if (!electron::Browser::Get()->is_ready())
|
||||
return false;
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
return is_available_ || (use_password_v10_ &&
|
||||
static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
->linux_storage_backend() == "basic_text");
|
||||
#else
|
||||
return is_available_;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SafeStorage::SetUsePasswordV10(bool use) {
|
||||
use_password_v10_ = use;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
std::string GetSelectedLinuxBackend() {
|
||||
std::string SafeStorage::GetSelectedLinuxBackend() {
|
||||
if (!electron::Browser::Get()->is_ready())
|
||||
return "unknown";
|
||||
return static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
@@ -49,8 +180,8 @@ std::string GetSelectedLinuxBackend() {
|
||||
}
|
||||
#endif
|
||||
|
||||
v8::Local<v8::Value> EncryptString(v8::Isolate* isolate,
|
||||
const std::string& plaintext) {
|
||||
v8::Local<v8::Value> SafeStorage::EncryptString(v8::Isolate* isolate,
|
||||
const std::string& plaintext) {
|
||||
if (!IsEncryptionAvailable()) {
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
gin_helper::ErrorThrower(isolate).ThrowError(
|
||||
@@ -77,7 +208,8 @@ v8::Local<v8::Value> EncryptString(v8::Isolate* isolate,
|
||||
return electron::Buffer::Copy(isolate, ciphertext).ToLocalChecked();
|
||||
}
|
||||
|
||||
std::string DecryptString(v8::Isolate* isolate, v8::Local<v8::Value> buffer) {
|
||||
std::string SafeStorage::DecryptString(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> buffer) {
|
||||
if (!IsEncryptionAvailable()) {
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
gin_helper::ErrorThrower(isolate).ThrowError(
|
||||
@@ -126,7 +258,92 @@ std::string DecryptString(v8::Isolate* isolate, v8::Local<v8::Value> buffer) {
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
v8::Local<v8::Promise> SafeStorage::encryptStringAsync(
|
||||
v8::Isolate* isolate,
|
||||
const std::string& plaintext) {
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
promise.RejectWithErrorMessage(
|
||||
"safeStorage cannot be used before app is ready");
|
||||
return handle;
|
||||
}
|
||||
|
||||
if (is_available_) {
|
||||
std::string ciphertext;
|
||||
bool encrypted = encryptor_->EncryptString(plaintext, &ciphertext);
|
||||
if (encrypted) {
|
||||
promise.Resolve(
|
||||
electron::Buffer::Copy(isolate, ciphertext).ToLocalChecked());
|
||||
} else {
|
||||
promise.RejectWithErrorMessage(
|
||||
"Error while encrypting the text provided to "
|
||||
"safeStorage.encryptStringAsync.");
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
pending_encrypts_.emplace_back(std::move(promise), std::move(plaintext));
|
||||
return handle;
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> SafeStorage::decryptStringAsync(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> buffer) {
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise(isolate);
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
promise.RejectWithErrorMessage(
|
||||
"safeStorage cannot be used before app is ready");
|
||||
return handle;
|
||||
}
|
||||
|
||||
if (!node::Buffer::HasInstance(buffer)) {
|
||||
promise.RejectWithErrorMessage(
|
||||
"Expected the first argument of decryptStringAsync() to be a buffer");
|
||||
return handle;
|
||||
}
|
||||
|
||||
const char* data = node::Buffer::Data(buffer);
|
||||
auto size = node::Buffer::Length(buffer);
|
||||
std::string ciphertext(data, size);
|
||||
|
||||
if (ciphertext.empty()) {
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("shouldReEncrypt", false);
|
||||
dict.Set("result", "");
|
||||
promise.Resolve(dict);
|
||||
return handle;
|
||||
}
|
||||
|
||||
if (is_available_) {
|
||||
std::string plaintext;
|
||||
os_crypt_async::Encryptor::DecryptFlags flags;
|
||||
bool decrypted = encryptor_->DecryptString(ciphertext, &plaintext, &flags);
|
||||
if (decrypted) {
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("shouldReEncrypt", flags.should_reencrypt);
|
||||
dict.Set("result", plaintext);
|
||||
promise.Resolve(dict);
|
||||
} else if (flags.temporarily_unavailable) {
|
||||
promise.RejectWithErrorMessage(
|
||||
"safeStorage.decryptStringAsync is temporarily unavailable. "
|
||||
"Please try again.");
|
||||
} else {
|
||||
promise.RejectWithErrorMessage(
|
||||
"Error while decrypting the ciphertext provided to "
|
||||
"safeStorage.decryptStringAsync.");
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
pending_decrypts_.emplace_back(std::move(promise), std::move(ciphertext));
|
||||
return handle;
|
||||
}
|
||||
|
||||
} // namespace electron::api
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
@@ -134,13 +351,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||
void* priv) {
|
||||
v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("decryptString", &DecryptString);
|
||||
dict.SetMethod("encryptString", &EncryptString);
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
dict.SetMethod("getSelectedStorageBackend", &GetSelectedLinuxBackend);
|
||||
#endif
|
||||
dict.SetMethod("isEncryptionAvailable", &IsEncryptionAvailable);
|
||||
dict.SetMethod("setUsePlainTextEncryption", &SetUsePasswordV10);
|
||||
dict.Set("safeStorage", electron::api::SafeStorage::Create(isolate));
|
||||
}
|
||||
|
||||
NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_safe_storage, Initialize)
|
||||
|
||||
126
shell/browser/api/electron_api_safe_storage.h
Normal file
126
shell/browser/api/electron_api_safe_storage.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2021 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SAFE_STORAGE_H_
|
||||
#define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SAFE_STORAGE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "components/os_crypt/async/common/encryptor.h"
|
||||
#include "shell/browser/browser_observer.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "shell/common/gin_helper/wrappable.h"
|
||||
|
||||
namespace v8 {
|
||||
class Context;
|
||||
class Isolate;
|
||||
class Object;
|
||||
class Value;
|
||||
template <class T>
|
||||
class Local;
|
||||
} // namespace v8
|
||||
|
||||
namespace gin {
|
||||
class ObjectTemplateBuilder;
|
||||
} // namespace gin
|
||||
|
||||
namespace gin_helper {
|
||||
template <typename T>
|
||||
class Handle;
|
||||
} // namespace gin_helper
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
class SafeStorage final : public gin_helper::DeprecatedWrappable<SafeStorage>,
|
||||
public gin_helper::EventEmitterMixin<SafeStorage>,
|
||||
private BrowserObserver {
|
||||
public:
|
||||
static gin_helper::Handle<SafeStorage> Create(v8::Isolate* isolate);
|
||||
|
||||
// gin_helper::Wrappable
|
||||
static gin::DeprecatedWrapperInfo kWrapperInfo;
|
||||
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
const char* GetTypeName() override;
|
||||
|
||||
// disable copy
|
||||
SafeStorage(const SafeStorage&) = delete;
|
||||
SafeStorage& operator=(const SafeStorage&) = delete;
|
||||
|
||||
protected:
|
||||
explicit SafeStorage(v8::Isolate* isolate);
|
||||
~SafeStorage() override;
|
||||
|
||||
private:
|
||||
// BrowserObserver:
|
||||
void OnFinishLaunching(base::DictValue launch_info) override;
|
||||
|
||||
void OnOsCryptReady(os_crypt_async::Encryptor encryptor);
|
||||
|
||||
bool IsEncryptionAvailable();
|
||||
|
||||
bool IsAsyncEncryptionAvailable();
|
||||
|
||||
void SetUsePasswordV10(bool use);
|
||||
|
||||
v8::Local<v8::Value> EncryptString(v8::Isolate* isolate,
|
||||
const std::string& plaintext);
|
||||
|
||||
std::string DecryptString(v8::Isolate* isolate, v8::Local<v8::Value> buffer);
|
||||
|
||||
v8::Local<v8::Promise> encryptStringAsync(v8::Isolate* isolate,
|
||||
const std::string& plaintext);
|
||||
|
||||
v8::Local<v8::Promise> decryptStringAsync(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> buffer);
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
std::string GetSelectedLinuxBackend();
|
||||
#endif
|
||||
|
||||
bool use_password_v10_ = false;
|
||||
|
||||
bool is_available_ = false;
|
||||
|
||||
std::optional<os_crypt_async::Encryptor> encryptor_;
|
||||
|
||||
// Pending encrypt operations waiting for encryptor to be ready.
|
||||
struct PendingEncrypt {
|
||||
PendingEncrypt(gin_helper::Promise<v8::Local<v8::Value>> promise,
|
||||
std::string plaintext);
|
||||
~PendingEncrypt();
|
||||
PendingEncrypt(PendingEncrypt&&);
|
||||
PendingEncrypt& operator=(PendingEncrypt&&);
|
||||
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise;
|
||||
std::string plaintext;
|
||||
};
|
||||
std::vector<PendingEncrypt> pending_encrypts_;
|
||||
|
||||
// Pending decrypt operations waiting for encryptor to be ready.
|
||||
struct PendingDecrypt {
|
||||
PendingDecrypt(gin_helper::Promise<gin_helper::Dictionary> promise,
|
||||
std::string ciphertext);
|
||||
~PendingDecrypt();
|
||||
PendingDecrypt(PendingDecrypt&&);
|
||||
PendingDecrypt& operator=(PendingDecrypt&&);
|
||||
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise;
|
||||
std::string ciphertext;
|
||||
};
|
||||
std::vector<PendingDecrypt> pending_decrypts_;
|
||||
};
|
||||
|
||||
} // namespace electron::api
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv);
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SAFE_STORAGE_H_
|
||||
@@ -192,9 +192,8 @@ void Browser::DidFinishLaunching(base::DictValue launch_info) {
|
||||
}
|
||||
|
||||
is_ready_ = true;
|
||||
if (ready_promise_) {
|
||||
if (ready_promise_)
|
||||
ready_promise_->Resolve();
|
||||
}
|
||||
|
||||
for (BrowserObserver& observer : observers_)
|
||||
observer.OnFinishLaunching(launch_info.Clone());
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/notimplemented.h"
|
||||
#include "base/path_service.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
@@ -46,6 +47,28 @@
|
||||
#include "chrome/browser/printing/print_job_manager.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
#include "chrome/browser/browser_features.h"
|
||||
#include "components/os_crypt/async/browser/freedesktop_secret_key_provider.h"
|
||||
#include "components/os_crypt/async/browser/secret_portal_key_provider.h"
|
||||
#include "components/password_manager/core/browser/password_manager_switches.h" // nogncheck
|
||||
#include "shell/common/application_info.h"
|
||||
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "components/os_crypt/async/browser/dpapi_key_provider.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include "chrome/common/chrome_features.h"
|
||||
#include "components/os_crypt/async/browser/keychain_key_provider.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
|
||||
#include "components/os_crypt/async/browser/posix_key_provider.h"
|
||||
#endif
|
||||
|
||||
BrowserProcessImpl::BrowserProcessImpl() {
|
||||
g_browser_process = this;
|
||||
}
|
||||
@@ -116,10 +139,16 @@ void BrowserProcessImpl::PostEarlyInitialization() {
|
||||
PrefServiceFactory prefs_factory;
|
||||
auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
|
||||
PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get());
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
OSCrypt::RegisterLocalPrefs(pref_registry.get());
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
os_crypt_async::SecretPortalKeyProvider::RegisterLocalPrefs(
|
||||
pref_registry.get());
|
||||
#endif
|
||||
|
||||
in_memory_pref_store_ = base::MakeRefCounted<ValueMapPrefStore>();
|
||||
ApplyProxyModeFromCommandLine(in_memory_pref_store());
|
||||
prefs_factory.set_command_line_prefs(in_memory_pref_store());
|
||||
@@ -419,16 +448,63 @@ void BrowserProcessImpl::CreateNetworkQualityObserver() {
|
||||
}
|
||||
|
||||
void BrowserProcessImpl::CreateOSCryptAsync() {
|
||||
// source: https://chromium-review.googlesource.com/c/chromium/src/+/4455776
|
||||
std::vector<std::pair<size_t, std::unique_ptr<os_crypt_async::KeyProvider>>>
|
||||
providers;
|
||||
|
||||
// For now, initialize OSCryptAsync with no providers. This delegates all
|
||||
// encryption operations to OSCrypt.
|
||||
// TODO(crbug.com/1373092): Add providers behind features, as support for them
|
||||
// is added.
|
||||
os_crypt_async_ = std::make_unique<os_crypt_async::OSCryptAsync>(
|
||||
std::vector<
|
||||
std::pair<size_t, std::unique_ptr<os_crypt_async::KeyProvider>>>());
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// The DPAPI key provider requires OSCrypt::Init to have already been called
|
||||
// to initialize the key storage. This happens in
|
||||
// BrowserMainPartsWin::PreCreateMainMessageLoop.
|
||||
providers.emplace_back(std::make_pair(
|
||||
/*precedence=*/10u,
|
||||
std::make_unique<os_crypt_async::DPAPIKeyProvider>(local_state())));
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
// Trigger async initialization of OSCrypt key providers.
|
||||
os_crypt_async_->GetInstance(base::DoNothing());
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
const auto password_store =
|
||||
cmd_line->GetSwitchValueASCII(password_manager::kPasswordStore);
|
||||
|
||||
if (base::FeatureList::IsEnabled(features::kDbusSecretPortal)) {
|
||||
// Use a higher priority than the FreedesktopSecretKeyProvider.
|
||||
providers.emplace_back(
|
||||
/*precedence=*/15u,
|
||||
std::make_unique<os_crypt_async::SecretPortalKeyProvider>(
|
||||
local_state(),
|
||||
base::FeatureList::IsEnabled(
|
||||
features::kSecretPortalKeyProviderUseForEncryption)));
|
||||
}
|
||||
|
||||
auto freedesktop_config =
|
||||
os_crypt_async::FreedesktopSecretKeyProvider::GetDefaultConfig();
|
||||
|
||||
const std::string app_name = electron::GetApplicationName();
|
||||
freedesktop_config.app_name = app_name;
|
||||
freedesktop_config.kwallet_folder = app_name + " Keys";
|
||||
freedesktop_config.key_name = app_name + " Safe Storage";
|
||||
|
||||
providers.emplace_back(
|
||||
/*precedence=*/10u,
|
||||
std::make_unique<os_crypt_async::FreedesktopSecretKeyProvider>(
|
||||
password_store, electron::GetApplicationName(), freedesktop_config,
|
||||
nullptr));
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
|
||||
// On other POSIX systems, this is the only key provider. On Linux, it is used
|
||||
// as a fallback.
|
||||
providers.emplace_back(
|
||||
/*precedence=*/5u, std::make_unique<os_crypt_async::PosixKeyProvider>());
|
||||
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
if (base::FeatureList::IsEnabled(features::kUseKeychainKeyProvider)) {
|
||||
providers.emplace_back(std::make_pair(
|
||||
/*precedence=*/10u,
|
||||
std::make_unique<os_crypt_async::KeychainKeyProvider>()));
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
os_crypt_async_ =
|
||||
std::make_unique<os_crypt_async::OSCryptAsync>(std::move(providers));
|
||||
}
|
||||
|
||||
@@ -469,6 +469,8 @@ int ElectronBrowserMainParts::PreMainMessageLoopRun() {
|
||||
DevToolsManagerDelegate::StartHttpHandler();
|
||||
}
|
||||
|
||||
fake_browser_process_->PreMainMessageLoopRun();
|
||||
|
||||
#if !BUILDFLAG(IS_MAC)
|
||||
// The corresponding call in macOS is in ElectronApplicationDelegate.
|
||||
Browser::Get()->WillFinishLaunching();
|
||||
@@ -478,8 +480,6 @@ int ElectronBrowserMainParts::PreMainMessageLoopRun() {
|
||||
// Notify observers that main thread message loop was initialized.
|
||||
Browser::Get()->PreMainMessageLoopRun();
|
||||
|
||||
fake_browser_process_->PreMainMessageLoopRun();
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
ui::SelectFileDialog::SetFactory(
|
||||
std::make_unique<ChromeSelectFileDialogFactory>());
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "net/http/http_util.h"
|
||||
#include "net/net_buildflags.h"
|
||||
#include "services/network/network_service.h"
|
||||
#include "services/network/public/cpp/cookie_encryption_provider_impl.h"
|
||||
#include "services/network/public/cpp/cors/origin_access_list.h"
|
||||
#include "shell/browser/browser_process_impl.h"
|
||||
#include "shell/browser/electron_browser_client.h"
|
||||
@@ -114,6 +115,18 @@ void NetworkContextService::ConfigureNetworkContextParams(
|
||||
network_context_params->enable_encrypted_cookies =
|
||||
electron::fuses::IsCookieEncryptionEnabled();
|
||||
|
||||
// If cookie encryption is enabled, we need to provide a cookie encryption
|
||||
// provider for the network service to use.
|
||||
if (network_context_params->enable_encrypted_cookies) {
|
||||
if (!cookie_encryption_provider_) {
|
||||
cookie_encryption_provider_ =
|
||||
std::make_unique<CookieEncryptionProviderImpl>(
|
||||
g_browser_process->os_crypt_async());
|
||||
}
|
||||
network_context_params->cookie_encryption_provider =
|
||||
cookie_encryption_provider_->BindNewRemote();
|
||||
}
|
||||
|
||||
network_context_params->file_paths->transport_security_persister_file_name =
|
||||
base::FilePath(chrome::kTransportSecurityPersisterFilename);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,16 @@
|
||||
#ifndef ELECTRON_SHELL_BROWSER_NET_NETWORK_CONTEXT_SERVICE_H_
|
||||
#define ELECTRON_SHELL_BROWSER_NET_NETWORK_CONTEXT_SERVICE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "chrome/browser/net/proxy_config_monitor.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom-forward.h"
|
||||
#include "services/network/public/mojom/network_context.mojom-forward.h"
|
||||
|
||||
class CookieEncryptionProviderImpl;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
} // namespace base
|
||||
@@ -46,6 +50,7 @@ class NetworkContextService : public KeyedService {
|
||||
|
||||
raw_ptr<ElectronBrowserContext> browser_context_;
|
||||
ProxyConfigMonitor proxy_config_monitor_;
|
||||
std::unique_ptr<CookieEncryptionProviderImpl> cookie_encryption_provider_;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -280,7 +280,12 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(
|
||||
// process, send it the required key.
|
||||
if (content::IsOutOfProcessNetworkService() &&
|
||||
electron::fuses::IsCookieEncryptionEnabled()) {
|
||||
// On Windows, OSCrypt Async manages the encryption key via the DPAPI key
|
||||
// provider, and there is no need to send the key separately to OSCrypt
|
||||
// sync.
|
||||
#if !BUILDFLAG(IS_WIN)
|
||||
network_service->SetEncryptionKey(OSCrypt::GetRawEncryptionKey());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user