#include "components/sync/driver/sync_service_crypto.h"
#include <utility>
#include "base/base64.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/task/sequenced_task_runner.h"
#include "components/os_crypt/sync/os_crypt.h"
#include "components/sync/base/passphrase_enums.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/trusted_vault_histograms.h"
#include "components/sync/engine/nigori/nigori.h"
#include "components/sync/engine/sync_string_conversions.h"
namespace syncer {
namespace {
enum class TrustedVaultFetchKeysAttemptForUMA {
kFirstAttempt,
kSecondAttempt,
kMaxValue = kSecondAttempt
};
class EmptyTrustedVaultClient : public TrustedVaultClient {
public:
EmptyTrustedVaultClient() = default;
~EmptyTrustedVaultClient() override = default;
void AddObserver(Observer* observer) override {}
void RemoveObserver(Observer* observer) override {}
void FetchKeys(
const CoreAccountInfo& account_info,
base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> cb)
override {
std::move(cb).Run({});
}
void StoreKeys(const std::string& gaia_id,
const std::vector<std::vector<uint8_t>>& keys,
int last_key_version) override {
NOTREACHED();
}
void MarkLocalKeysAsStale(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override {
std::move(cb).Run(false);
}
void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override {
std::move(cb).Run(false);
}
void AddTrustedRecoveryMethod(const std::string& gaia_id,
const std::vector<uint8_t>& public_key,
int method_type_hint,
base::OnceClosure cb) override {
NOTREACHED();
}
void ClearLocalDataForAccount(const CoreAccountInfo& account_info) override {
NOTREACHED();
}
};
class SyncEncryptionObserverProxy : public SyncEncryptionHandler::Observer {
public:
SyncEncryptionObserverProxy(
base::WeakPtr<SyncEncryptionHandler::Observer> observer,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: observer_(observer), task_runner_(std::move(task_runner)) {}
void OnPassphraseRequired(
const KeyDerivationParams& key_derivation_params,
const sync_pb::EncryptedData& pending_keys) override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&SyncEncryptionHandler::Observer::OnPassphraseRequired,
observer_, key_derivation_params, pending_keys));
}
void OnPassphraseAccepted() override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&SyncEncryptionHandler::Observer::OnPassphraseAccepted,
observer_));
}
void OnTrustedVaultKeyRequired() override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SyncEncryptionHandler::Observer::OnTrustedVaultKeyRequired,
observer_));
}
void OnTrustedVaultKeyAccepted() override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SyncEncryptionHandler::Observer::OnTrustedVaultKeyAccepted,
observer_));
}
void OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
bool encrypt_everything) override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SyncEncryptionHandler::Observer::OnEncryptedTypesChanged,
observer_, encrypted_types, encrypt_everything));
}
void OnCryptographerStateChanged(Cryptographer* cryptographer,
bool has_pending_keys) override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SyncEncryptionHandler::Observer::OnCryptographerStateChanged,
observer_, nullptr, has_pending_keys));
}
void OnPassphraseTypeChanged(PassphraseType type,
base::Time passphrase_time) override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SyncEncryptionHandler::Observer::OnPassphraseTypeChanged,
observer_, type, passphrase_time));
}
private:
base::WeakPtr<SyncEncryptionHandler::Observer> observer_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
};
TrustedVaultClient* ResoveNullClient(TrustedVaultClient* client) {
if (client) {
return client;
}
static base::NoDestructor<EmptyTrustedVaultClient> empty_client;
return empty_client.get();
}
bool CheckNigoriAgainstPendingKeys(const Nigori& nigori,
const sync_pb::EncryptedData& pending_keys) {
DCHECK(pending_keys.has_blob());
std::string plaintext;
bool decrypt_result = nigori.Decrypt(pending_keys.blob(), &plaintext);
DVLOG_IF(1, !decrypt_result) << "Passphrase failed to decrypt pending keys.";
return decrypt_result;
}
std::unique_ptr<Nigori> ReadNigoriFromBootstrapToken(
const std::string& bootstrap_token) {
if (bootstrap_token.empty()) {
return nullptr;
}
std::string decoded_key;
if (!base::Base64Decode(bootstrap_token, &decoded_key)) {
return nullptr;
}
std::string decrypted_key;
if (!OSCrypt::DecryptString(decoded_key, &decrypted_key)) {
return nullptr;
}
sync_pb::NigoriKey key;
if (!key.ParseFromString(decrypted_key)) {
return nullptr;
}
return Nigori::CreateByImport(key.deprecated_user_key(), key.encryption_key(),
key.mac_key());
}
std::string SerializeNigoriAsBootstrapToken(const Nigori& nigori) {
sync_pb::NigoriKey proto;
nigori.ExportKeys(proto.mutable_deprecated_user_key(),
proto.mutable_encryption_key(), proto.mutable_mac_key());
const std::string serialized_key = proto.SerializeAsString();
if (serialized_key.empty()) {
return std::string();
}
std::string encrypted_key;
if (!OSCrypt::EncryptString(serialized_key, &encrypted_key)) {
return std::string();
}
std::string encoded_key;
base::Base64Encode(encrypted_key, &encoded_key);
return encoded_key;
}
}
SyncServiceCrypto::State::State()
: passphrase_key_derivation_params(KeyDerivationParams::CreateForPbkdf2()) {
}
SyncServiceCrypto::State::~State() = default;
SyncServiceCrypto::SyncServiceCrypto(Delegate* delegate,
TrustedVaultClient* trusted_vault_client)
: delegate_(delegate),
trusted_vault_client_(ResoveNullClient(trusted_vault_client)) {
DCHECK(delegate_);
DCHECK(trusted_vault_client_);
trusted_vault_client_->AddObserver(this);
}
SyncServiceCrypto::~SyncServiceCrypto() {
trusted_vault_client_->RemoveObserver(this);
}
void SyncServiceCrypto::Reset() {
state_ = State();
}
base::Time SyncServiceCrypto::GetExplicitPassphraseTime() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return state_.cached_explicit_passphrase_time;
}
bool SyncServiceCrypto::IsPassphraseRequired() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone:
case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return false;
case RequiredUserAction::kPassphraseRequired:
return true;
}
NOTREACHED();
return false;
}
bool SyncServiceCrypto::IsUsingExplicitPassphrase() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return IsExplicitPassphrase(state_.cached_passphrase_type);
}
bool SyncServiceCrypto::IsTrustedVaultKeyRequired() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return state_.required_user_action ==
RequiredUserAction::kTrustedVaultKeyRequired ||
state_.required_user_action ==
RequiredUserAction::kTrustedVaultKeyRequiredButFetching;
}
bool SyncServiceCrypto::IsTrustedVaultRecoverabilityDegraded() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return state_.required_user_action ==
RequiredUserAction::kTrustedVaultRecoverabilityDegraded;
}
bool SyncServiceCrypto::IsEncryptEverythingEnabled() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(state_.engine);
return state_.encrypt_everything;
}
void SyncServiceCrypto::SetEncryptionPassphrase(const std::string& passphrase) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(state_.engine);
DCHECK(!passphrase.empty());
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
break;
case RequiredUserAction::kPassphraseRequired:
case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
NOTREACHED()
<< "Can not set explicit passphrase when decryption is needed.";
return;
}
DVLOG(1) << "Setting explicit passphrase for encryption.";
DCHECK(!IsExplicitPassphrase(state_.cached_passphrase_type));
const auto key_derivation_params =
KeyDerivationParams::CreateForScrypt(Nigori::GenerateScryptSalt());
state_.engine->SetEncryptionPassphrase(passphrase, key_derivation_params);
std::unique_ptr<Nigori> nigori =
Nigori::CreateByDerivation(key_derivation_params, passphrase);
DCHECK(nigori);
delegate_->SetEncryptionBootstrapToken(
SerializeNigoriAsBootstrapToken(*nigori));
}
bool SyncServiceCrypto::SetDecryptionPassphrase(const std::string& passphrase) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(state_.engine);
DCHECK(!passphrase.empty());
DCHECK(state_.cached_pending_keys.has_blob());
if (state_.cached_passphrase_type != PassphraseType::kCustomPassphrase) {
DCHECK_EQ(state_.passphrase_key_derivation_params.method(),
KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003);
}
std::unique_ptr<Nigori> nigori = Nigori::CreateByDerivation(
state_.passphrase_key_derivation_params, passphrase);
DCHECK(nigori);
delegate_->SetEncryptionBootstrapToken(
SerializeNigoriAsBootstrapToken(*nigori));
return SetDecryptionKeyWithoutUpdatingBootstrapToken(std::move(nigori));
}
void SyncServiceCrypto::SetDecryptionNigoriKey(std::unique_ptr<Nigori> nigori) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(nigori);
if (state_.required_user_action != RequiredUserAction::kPassphraseRequired) {
return;
}
delegate_->SetEncryptionBootstrapToken(
SerializeNigoriAsBootstrapToken(*nigori));
if (state_.engine) {
SetDecryptionKeyWithoutUpdatingBootstrapToken(std::move(nigori));
}
}
std::unique_ptr<Nigori> SyncServiceCrypto::GetDecryptionNigoriKey() const {
return ReadNigoriFromBootstrapToken(delegate_->GetEncryptionBootstrapToken());
}
bool SyncServiceCrypto::IsTrustedVaultKeyRequiredStateKnown() const {
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kFetchingTrustedVaultKeys:
return false;
case RequiredUserAction::kNone:
case RequiredUserAction::kPassphraseRequired:
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return true;
}
NOTREACHED();
return false;
}
PassphraseType SyncServiceCrypto::GetPassphraseType() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return state_.cached_passphrase_type;
}
void SyncServiceCrypto::SetSyncEngine(const CoreAccountInfo& account_info,
SyncEngine* engine) {
DCHECK(engine);
state_.account_info = account_info;
state_.engine = engine;
switch (state_.required_user_action) {
case RequiredUserAction::kNone:
DCHECK_NE(state_.cached_passphrase_type,
PassphraseType::kTrustedVaultPassphrase);
break;
case RequiredUserAction::kUnknownDuringInitialization:
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
RefreshIsRecoverabilityDegraded();
break;
case RequiredUserAction::kFetchingTrustedVaultKeys:
FetchTrustedVaultKeys(false);
break;
case RequiredUserAction::kPassphraseRequired:
MaybeSetDecryptionKeyFromBootstrapToken();
break;
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
NOTREACHED();
break;
}
}
std::unique_ptr<SyncEncryptionHandler::Observer>
SyncServiceCrypto::GetEncryptionObserverProxy() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return std::make_unique<SyncEncryptionObserverProxy>(
weak_factory_.GetWeakPtr(),
base::SequencedTaskRunner::GetCurrentDefault());
}
ModelTypeSet SyncServiceCrypto::GetEncryptedDataTypes() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(state_.encrypted_types.HasAll(AlwaysEncryptedUserTypes()));
return state_.encrypted_types;
}
bool SyncServiceCrypto::HasCryptoError() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return false;
case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kPassphraseRequired:
return true;
}
NOTREACHED();
return false;
}
void SyncServiceCrypto::OnPassphraseRequired(
const KeyDerivationParams& key_derivation_params,
const sync_pb::EncryptedData& pending_keys) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
state_.cached_pending_keys = pending_keys;
state_.passphrase_key_derivation_params = key_derivation_params;
DVLOG(1) << "Passphrase required.";
UpdateRequiredUserActionAndNotify(RequiredUserAction::kPassphraseRequired);
delegate_->ReconfigureDataTypesDueToCrypto();
MaybeSetDecryptionKeyFromBootstrapToken();
}
void SyncServiceCrypto::OnPassphraseAccepted() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
state_.cached_pending_keys.clear_blob();
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
delegate_->ReconfigureDataTypesDueToCrypto();
}
void SyncServiceCrypto::OnTrustedVaultKeyRequired() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (state_.required_user_action != RequiredUserAction::kNone &&
state_.required_user_action !=
RequiredUserAction::kUnknownDuringInitialization) {
return;
}
UpdateRequiredUserActionAndNotify(
RequiredUserAction::kFetchingTrustedVaultKeys);
if (!state_.engine) {
return;
}
FetchTrustedVaultKeys(false);
}
void SyncServiceCrypto::OnTrustedVaultKeyAccepted() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone:
case RequiredUserAction::kPassphraseRequired:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return;
case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
break;
}
DCHECK(state_.engine);
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
RefreshIsRecoverabilityDegraded();
delegate_->ReconfigureDataTypesDueToCrypto();
}
void SyncServiceCrypto::OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
bool encrypt_everything) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
state_.encrypted_types = encrypted_types;
state_.encrypt_everything = encrypt_everything;
DVLOG(1) << "Encrypted types changed to "
<< ModelTypeSetToDebugString(state_.encrypted_types)
<< " (encrypt everything is set to "
<< (state_.encrypt_everything ? "true" : "false") << ")";
DCHECK(state_.encrypted_types.HasAll(AlwaysEncryptedUserTypes()));
delegate_->CryptoStateChanged();
}
void SyncServiceCrypto::OnCryptographerStateChanged(
Cryptographer* cryptographer,
bool has_pending_keys) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void SyncServiceCrypto::OnPassphraseTypeChanged(PassphraseType type,
base::Time passphrase_time) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(1) << "Passphrase type changed to " << PassphraseTypeToString(type);
state_.cached_passphrase_type = type;
state_.cached_explicit_passphrase_time = passphrase_time;
if (type != PassphraseType::kTrustedVaultPassphrase &&
state_.required_user_action ==
RequiredUserAction::kTrustedVaultRecoverabilityDegraded) {
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
}
delegate_->CryptoStateChanged();
}
void SyncServiceCrypto::OnTrustedVaultKeysChanged() {
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone:
case RequiredUserAction::kPassphraseRequired:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return;
case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
state_.deferred_trusted_vault_fetch_keys_pending = true;
return;
case RequiredUserAction::kTrustedVaultKeyRequired:
UpdateRequiredUserActionAndNotify(
RequiredUserAction::kTrustedVaultKeyRequiredButFetching);
break;
}
FetchTrustedVaultKeys(false);
}
void SyncServiceCrypto::OnTrustedVaultRecoverabilityChanged() {
if (!state_.engine) {
return;
}
RefreshIsRecoverabilityDegraded();
}
void SyncServiceCrypto::FetchTrustedVaultKeys(bool is_second_fetch_attempt) {
DCHECK(state_.engine);
DCHECK(state_.required_user_action ==
RequiredUserAction::kFetchingTrustedVaultKeys ||
state_.required_user_action ==
RequiredUserAction::kTrustedVaultKeyRequiredButFetching);
base::UmaHistogramEnumeration(
"Sync.TrustedVaultFetchKeysAttempt",
is_second_fetch_attempt
? TrustedVaultFetchKeysAttemptForUMA::kSecondAttempt
: TrustedVaultFetchKeysAttemptForUMA::kFirstAttempt);
if (!is_second_fetch_attempt) {
state_.deferred_trusted_vault_fetch_keys_pending = false;
}
trusted_vault_client_->FetchKeys(
state_.account_info,
base::BindOnce(&SyncServiceCrypto::TrustedVaultKeysFetchedFromClient,
weak_factory_.GetWeakPtr(), is_second_fetch_attempt));
}
void SyncServiceCrypto::TrustedVaultKeysFetchedFromClient(
bool is_second_fetch_attempt,
const std::vector<std::vector<uint8_t>>& keys) {
if (state_.required_user_action !=
RequiredUserAction::kFetchingTrustedVaultKeys &&
state_.required_user_action !=
RequiredUserAction::kTrustedVaultKeyRequiredButFetching) {
return;
}
DCHECK(state_.engine);
base::UmaHistogramCounts100("Sync.TrustedVaultFetchedKeysCount", keys.size());
if (keys.empty()) {
FetchTrustedVaultKeysCompletedButInsufficient();
return;
}
state_.engine->AddTrustedVaultDecryptionKeys(
keys,
base::BindOnce(&SyncServiceCrypto::TrustedVaultKeysAdded,
weak_factory_.GetWeakPtr(), is_second_fetch_attempt));
}
void SyncServiceCrypto::TrustedVaultKeysAdded(bool is_second_fetch_attempt) {
bool success = state_.required_user_action !=
RequiredUserAction::kFetchingTrustedVaultKeys &&
state_.required_user_action !=
RequiredUserAction::kTrustedVaultKeyRequiredButFetching;
base::UmaHistogramBoolean("Sync.TrustedVaultAddKeysAttemptIsSuccessful",
success);
if (success) {
return;
}
trusted_vault_client_->MarkLocalKeysAsStale(
state_.account_info,
base::BindOnce(&SyncServiceCrypto::TrustedVaultKeysMarkedAsStale,
weak_factory_.GetWeakPtr(), is_second_fetch_attempt));
}
void SyncServiceCrypto::TrustedVaultKeysMarkedAsStale(
bool is_second_fetch_attempt,
bool result) {
if (state_.required_user_action !=
RequiredUserAction::kFetchingTrustedVaultKeys &&
state_.required_user_action !=
RequiredUserAction::kTrustedVaultKeyRequiredButFetching) {
return;
}
if (!result || is_second_fetch_attempt) {
FetchTrustedVaultKeysCompletedButInsufficient();
return;
}
FetchTrustedVaultKeys(true);
}
void SyncServiceCrypto::FetchTrustedVaultKeysCompletedButInsufficient() {
DCHECK(state_.required_user_action ==
RequiredUserAction::kFetchingTrustedVaultKeys ||
state_.required_user_action ==
RequiredUserAction::kTrustedVaultKeyRequiredButFetching);
if (state_.deferred_trusted_vault_fetch_keys_pending) {
FetchTrustedVaultKeys(false);
return;
}
UpdateRequiredUserActionAndNotify(
RequiredUserAction::kTrustedVaultKeyRequired);
delegate_->ReconfigureDataTypesDueToCrypto();
}
void SyncServiceCrypto::UpdateRequiredUserActionAndNotify(
RequiredUserAction new_required_user_action) {
DCHECK_NE(new_required_user_action,
RequiredUserAction::kUnknownDuringInitialization);
if (state_.required_user_action == new_required_user_action) {
return;
}
state_.required_user_action = new_required_user_action;
delegate_->CryptoRequiredUserActionChanged();
}
void SyncServiceCrypto::RefreshIsRecoverabilityDegraded() {
DCHECK(state_.engine);
if (state_.cached_passphrase_type !=
PassphraseType::kTrustedVaultPassphrase) {
return;
}
switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kPassphraseRequired:
return;
case RequiredUserAction::kNone:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
break;
}
trusted_vault_client_->GetIsRecoverabilityDegraded(
state_.account_info,
base::BindOnce(&SyncServiceCrypto::GetIsRecoverabilityDegradedCompleted,
weak_factory_.GetWeakPtr()));
}
void SyncServiceCrypto::GetIsRecoverabilityDegradedCompleted(
bool is_recoverability_degraded) {
if (state_.cached_passphrase_type !=
PassphraseType::kTrustedVaultPassphrase) {
DCHECK_NE(state_.required_user_action,
RequiredUserAction::kTrustedVaultRecoverabilityDegraded);
return;
}
if (is_recoverability_degraded &&
state_.required_user_action == RequiredUserAction::kNone) {
UpdateRequiredUserActionAndNotify(
RequiredUserAction::kTrustedVaultRecoverabilityDegraded);
delegate_->CryptoStateChanged();
}
if (!is_recoverability_degraded &&
state_.required_user_action ==
RequiredUserAction::kTrustedVaultRecoverabilityDegraded) {
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
delegate_->CryptoStateChanged();
}
if (!initial_trusted_vault_recoverability_logged_to_uma_) {
DCHECK(state_.engine);
initial_trusted_vault_recoverability_logged_to_uma_ = true;
RecordTrustedVaultHistogramBooleanWithMigrationSuffix(
"Sync.TrustedVaultRecoverabilityDegradedOnStartup",
is_recoverability_degraded, state_.engine->GetDetailedStatus());
}
}
bool SyncServiceCrypto::SetDecryptionKeyWithoutUpdatingBootstrapToken(
std::unique_ptr<Nigori> nigori) {
DCHECK(nigori);
DCHECK(state_.cached_pending_keys.has_blob());
if (!CheckNigoriAgainstPendingKeys(*nigori, state_.cached_pending_keys)) {
return false;
}
state_.engine->SetExplicitPassphraseDecryptionKey(std::move(nigori));
OnPassphraseAccepted();
return true;
}
void SyncServiceCrypto::MaybeSetDecryptionKeyFromBootstrapToken() {
if (!state_.engine) {
return;
}
std::unique_ptr<Nigori> nigori =
ReadNigoriFromBootstrapToken(delegate_->GetEncryptionBootstrapToken());
if (!nigori) {
return;
}
SetDecryptionKeyWithoutUpdatingBootstrapToken(std::move(nigori));
}
}