Commit 1ac641df authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

[sync] Expose trusted vault recoverability state in SyncUserSettings

This is intended to be used as an indication to the UI that the user
should take action to improve recoverability of the sync-ed data.

This patch introduces basic plumbing in TrustedVaultClient with TODOs
to address platform-specific implementations in later patches.
Meanwhile, StandaloneTrustedVaultClient is extended with test-only
APIs for integration tests.

Change-Id: Ic255e502d9e33b145272903dc2b7c3a7ec2a1cd8
Bug: 1081649
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2329751Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#793231}
parent 7e4fb727
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "components/sync/nigori/nigori.h" #include "components/sync/nigori/nigori.h"
#include "components/sync/nigori/nigori_test_utils.h" #include "components/sync/nigori/nigori_test_utils.h"
#include "components/sync/test/fake_server/fake_server_nigori_helper.h" #include "components/sync/test/fake_server/fake_server_nigori_helper.h"
#include "components/sync/trusted_vault/standalone_trusted_vault_client.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "content/public/test/test_launcher.h" #include "content/public/test/test_launcher.h"
#include "crypto/ec_private_key.h" #include "crypto/ec_private_key.h"
...@@ -50,6 +51,8 @@ using syncer::Pbkdf2KeyParamsForTesting; ...@@ -50,6 +51,8 @@ using syncer::Pbkdf2KeyParamsForTesting;
using testing::NotNull; using testing::NotNull;
using testing::SizeIs; using testing::SizeIs;
const char kGaiaId[] = "gaia_id_for_user_gmail.com";
MATCHER_P(IsDataEncryptedWith, key_params, "") { MATCHER_P(IsDataEncryptedWith, key_params, "") {
const sync_pb::EncryptedData& encrypted_data = arg; const sync_pb::EncryptedData& encrypted_data = arg;
std::unique_ptr<syncer::Nigori> nigori = syncer::Nigori::CreateByDerivation( std::unique_ptr<syncer::Nigori> nigori = syncer::Nigori::CreateByDerivation(
...@@ -88,7 +91,6 @@ MATCHER_P4(StatusLabelsMatch, ...@@ -88,7 +91,6 @@ MATCHER_P4(StatusLabelsMatch,
GURL GetTrustedVaultRetrievalURL( GURL GetTrustedVaultRetrievalURL(
const net::test_server::EmbeddedTestServer& test_server, const net::test_server::EmbeddedTestServer& test_server,
const std::vector<uint8_t>& encryption_key) { const std::vector<uint8_t>& encryption_key) {
const char kGaiaId[] = "gaia_id_for_user_gmail.com";
// encryption_keys_retrieval.html would populate encryption key to sync // encryption_keys_retrieval.html would populate encryption key to sync
// service upon loading. Key is provided as part of URL and needs to be // service upon loading. Key is provided as part of URL and needs to be
// encoded with Base64, because |encryption_key| is binary. // encoded with Base64, because |encryption_key| is binary.
...@@ -425,10 +427,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriSyncTestWithNotAwaitQuiescence, ...@@ -425,10 +427,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriSyncTestWithNotAwaitQuiescence,
class SingleClientNigoriWithWebApiTest : public SyncTest { class SingleClientNigoriWithWebApiTest : public SyncTest {
public: public:
SingleClientNigoriWithWebApiTest() : SyncTest(SINGLE_CLIENT) { SingleClientNigoriWithWebApiTest() : SyncTest(SINGLE_CLIENT) {}
override_features_.InitAndEnableFeature(
switches::kSyncSupportTrustedVaultPassphrase);
}
~SingleClientNigoriWithWebApiTest() override = default; ~SingleClientNigoriWithWebApiTest() override = default;
// InProcessBrowserTest: // InProcessBrowserTest:
...@@ -445,8 +444,6 @@ class SingleClientNigoriWithWebApiTest : public SyncTest { ...@@ -445,8 +444,6 @@ class SingleClientNigoriWithWebApiTest : public SyncTest {
} }
private: private:
base::test::ScopedFeatureList override_features_;
DISALLOW_COPY_AND_ASSIGN(SingleClientNigoriWithWebApiTest); DISALLOW_COPY_AND_ASSIGN(SingleClientNigoriWithWebApiTest);
}; };
...@@ -507,6 +504,12 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiTest, ...@@ -507,6 +504,12 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiTest,
sync_ui_util::GetStatusLabels(GetProfile(0)), sync_ui_util::GetStatusLabels(GetProfile(0)),
StatusLabelsMatch(sync_ui_util::SYNCED, IDS_SYNC_ACCOUNT_SYNCING, StatusLabelsMatch(sync_ui_util::SYNCED, IDS_SYNC_ACCOUNT_SYNCING,
IDS_SETTINGS_EMPTY_STRING, sync_ui_util::NO_ACTION)); IDS_SETTINGS_EMPTY_STRING, sync_ui_util::NO_ACTION));
#if !defined(OS_CHROMEOS)
// Verify the profile-menu error string is empty.
EXPECT_EQ(sync_ui_util::NO_SYNC_ERROR,
sync_ui_util::GetAvatarSyncErrorType(GetProfile(0)));
#endif // !defined(OS_CHROMEOS)
} }
IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiTest, IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiTest,
...@@ -551,8 +554,21 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiTest, ...@@ -551,8 +554,21 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiTest,
EXPECT_FALSE(GetSyncService(0) EXPECT_FALSE(GetSyncService(0)
->GetUserSettings() ->GetUserSettings()
->IsTrustedVaultKeyRequiredForPreferredDataTypes()); ->IsTrustedVaultKeyRequiredForPreferredDataTypes());
EXPECT_FALSE(GetSyncService(0)
->GetUserSettings()
->IsTrustedVaultRecoverabilityDegraded());
EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS)); EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS));
EXPECT_FALSE(sync_ui_util::ShouldShowSyncKeysMissingError(GetSyncService(0))); EXPECT_FALSE(sync_ui_util::ShouldShowSyncKeysMissingError(GetSyncService(0)));
EXPECT_THAT(
sync_ui_util::GetStatusLabels(GetProfile(0)),
StatusLabelsMatch(sync_ui_util::SYNCED, IDS_SYNC_ACCOUNT_SYNCING,
IDS_SETTINGS_EMPTY_STRING, sync_ui_util::NO_ACTION));
#if !defined(OS_CHROMEOS)
// Verify the profile-menu error string is empty.
EXPECT_EQ(sync_ui_util::NO_SYNC_ERROR,
sync_ui_util::GetAvatarSyncErrorType(GetProfile(0)));
#endif // !defined(OS_CHROMEOS)
} }
IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(
...@@ -880,4 +896,54 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiFromUntrustedOriginTest, ...@@ -880,4 +896,54 @@ IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithWebApiFromUntrustedOriginTest,
->IsTrustedVaultKeyRequiredForPreferredDataTypes()); ->IsTrustedVaultKeyRequiredForPreferredDataTypes());
} }
class SingleClientNigoriWithRecoverySyncTest : public SyncTest {
public:
SingleClientNigoriWithRecoverySyncTest() : SyncTest(SINGLE_CLIENT) {
override_features_.InitAndEnableFeature(
switches::kSyncSupportTrustedVaultPassphraseRecovery);
}
~SingleClientNigoriWithRecoverySyncTest() override = default;
private:
base::test::ScopedFeatureList override_features_;
DISALLOW_COPY_AND_ASSIGN(SingleClientNigoriWithRecoverySyncTest);
};
IN_PROC_BROWSER_TEST_F(SingleClientNigoriWithRecoverySyncTest,
ShouldReportDegradedTrustedVaultRecoverability) {
const std::vector<uint8_t> kTestEncryptionKey = {1, 2, 3, 4};
// Mimic the account being already using a trusted vault passphrase.
SetNigoriInFakeServer(BuildTrustedVaultNigoriSpecifics({kTestEncryptionKey}),
GetFakeServer());
// Mimic the key being available upon startup but recoverability degraded.
ASSERT_TRUE(SetupClients());
static_cast<syncer::StandaloneTrustedVaultClient*>(
GetSyncService(0)->GetSyncClientForTest()->GetTrustedVaultClient())
->SetRecoverabilityDegradedForTesting();
GetSyncService(0)->AddTrustedVaultDecryptionKeysFromWeb(
kGaiaId, {kTestEncryptionKey}, /*last_key_version=*/1);
ASSERT_TRUE(SetupSync());
ASSERT_EQ(syncer::PassphraseType::kTrustedVaultPassphrase,
GetSyncService(0)->GetUserSettings()->GetPassphraseType());
ASSERT_FALSE(GetSyncService(0)
->GetUserSettings()
->IsTrustedVaultKeyRequiredForPreferredDataTypes());
ASSERT_FALSE(sync_ui_util::ShouldShowSyncKeysMissingError(GetSyncService(0)));
EXPECT_TRUE(GetSyncService(0)
->GetUserSettings()
->IsTrustedVaultRecoverabilityDegraded());
// No messages expected in settings.
EXPECT_THAT(
sync_ui_util::GetStatusLabels(GetProfile(0)),
StatusLabelsMatch(sync_ui_util::SYNCED, IDS_SYNC_ACCOUNT_SYNCING,
IDS_SETTINGS_EMPTY_STRING, sync_ui_util::NO_ACTION));
}
} // namespace } // namespace
...@@ -129,3 +129,11 @@ void TrustedVaultClientAndroid::MarkKeysAsStale( ...@@ -129,3 +129,11 @@ void TrustedVaultClientAndroid::MarkKeysAsStale(
Java_TrustedVaultClient_markKeysAsStale(env, reinterpret_cast<intptr_t>(this), Java_TrustedVaultClient_markKeysAsStale(env, reinterpret_cast<intptr_t>(this),
java_account_info); java_account_info);
} }
void TrustedVaultClientAndroid::GetIsRecoverabilityDegraded(
const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) {
// TODO(crbug.com/1100279): Needs implementation.
NOTIMPLEMENTED();
std::move(cb).Run(false);
}
...@@ -58,6 +58,8 @@ class TrustedVaultClientAndroid : public syncer::TrustedVaultClient { ...@@ -58,6 +58,8 @@ class TrustedVaultClientAndroid : public syncer::TrustedVaultClient {
void RemoveAllStoredKeys() override; void RemoveAllStoredKeys() override;
void MarkKeysAsStale(const CoreAccountInfo& account_info, void MarkKeysAsStale(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override; base::OnceCallback<void(bool)> cb) override;
void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override;
private: private:
// Struct representing an in-flight FetchKeys() call invoked from C++. // Struct representing an in-flight FetchKeys() call invoked from C++.
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "components/sync/base/sync_prefs.h" #include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/sync_driver_switches.h" #include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_service.h"
#include "components/sync/engine/sync_engine_switches.h"
#include "components/sync/engine/sync_string_conversions.h" #include "components/sync/engine/sync_string_conversions.h"
#include "components/sync/nigori/nigori.h" #include "components/sync/nigori/nigori.h"
...@@ -66,6 +67,11 @@ class EmptyTrustedVaultClient : public TrustedVaultClient { ...@@ -66,6 +67,11 @@ class EmptyTrustedVaultClient : public TrustedVaultClient {
base::OnceCallback<void(bool)> cb) override { base::OnceCallback<void(bool)> cb) override {
std::move(cb).Run(false); std::move(cb).Run(false);
} }
void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override {
std::move(cb).Run(false);
}
}; };
// A SyncEncryptionHandler::Observer implementation that simply posts all calls // A SyncEncryptionHandler::Observer implementation that simply posts all calls
...@@ -241,6 +247,7 @@ bool SyncServiceCrypto::IsPassphraseRequired() const { ...@@ -241,6 +247,7 @@ bool SyncServiceCrypto::IsPassphraseRequired() const {
case RequiredUserAction::kFetchingTrustedVaultKeys: case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired: case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching: case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return false; return false;
case RequiredUserAction::kPassphraseRequiredForDecryption: case RequiredUserAction::kPassphraseRequiredForDecryption:
case RequiredUserAction::kPassphraseRequiredForEncryption: case RequiredUserAction::kPassphraseRequiredForEncryption:
...@@ -264,6 +271,12 @@ bool SyncServiceCrypto::IsTrustedVaultKeyRequired() const { ...@@ -264,6 +271,12 @@ bool SyncServiceCrypto::IsTrustedVaultKeyRequired() const {
RequiredUserAction::kTrustedVaultKeyRequiredButFetching; RequiredUserAction::kTrustedVaultKeyRequiredButFetching;
} }
bool SyncServiceCrypto::IsTrustedVaultRecoverabilityDegraded() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return state_.required_user_action ==
RequiredUserAction::kTrustedVaultRecoverabilityDegraded;
}
void SyncServiceCrypto::EnableEncryptEverything() { void SyncServiceCrypto::EnableEncryptEverything() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(state_.engine); DCHECK(state_.engine);
...@@ -290,6 +303,7 @@ void SyncServiceCrypto::SetEncryptionPassphrase(const std::string& passphrase) { ...@@ -290,6 +303,7 @@ void SyncServiceCrypto::SetEncryptionPassphrase(const std::string& passphrase) {
switch (state_.required_user_action) { switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization: case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone: case RequiredUserAction::kNone:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
break; break;
case RequiredUserAction::kPassphraseRequiredForDecryption: case RequiredUserAction::kPassphraseRequiredForDecryption:
case RequiredUserAction::kFetchingTrustedVaultKeys: case RequiredUserAction::kFetchingTrustedVaultKeys:
...@@ -372,6 +386,7 @@ bool SyncServiceCrypto::IsTrustedVaultKeyRequiredStateKnown() const { ...@@ -372,6 +386,7 @@ bool SyncServiceCrypto::IsTrustedVaultKeyRequiredStateKnown() const {
case RequiredUserAction::kTrustedVaultKeyRequired: case RequiredUserAction::kTrustedVaultKeyRequired:
case RequiredUserAction::kTrustedVaultKeyRequiredButFetching: case RequiredUserAction::kTrustedVaultKeyRequiredButFetching:
case RequiredUserAction::kPassphraseRequiredForEncryption: case RequiredUserAction::kPassphraseRequiredForEncryption:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return true; return true;
} }
NOTREACHED(); NOTREACHED();
...@@ -402,6 +417,7 @@ bool SyncServiceCrypto::HasCryptoError() const { ...@@ -402,6 +417,7 @@ bool SyncServiceCrypto::HasCryptoError() const {
switch (state_.required_user_action) { switch (state_.required_user_action) {
case RequiredUserAction::kUnknownDuringInitialization: case RequiredUserAction::kUnknownDuringInitialization:
case RequiredUserAction::kNone: case RequiredUserAction::kNone:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return false; return false;
case RequiredUserAction::kFetchingTrustedVaultKeys: case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired: case RequiredUserAction::kTrustedVaultKeyRequired:
...@@ -495,6 +511,7 @@ void SyncServiceCrypto::OnTrustedVaultKeyAccepted() { ...@@ -495,6 +511,7 @@ void SyncServiceCrypto::OnTrustedVaultKeyAccepted() {
case RequiredUserAction::kNone: case RequiredUserAction::kNone:
case RequiredUserAction::kPassphraseRequiredForDecryption: case RequiredUserAction::kPassphraseRequiredForDecryption:
case RequiredUserAction::kPassphraseRequiredForEncryption: case RequiredUserAction::kPassphraseRequiredForEncryption:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
return; return;
case RequiredUserAction::kFetchingTrustedVaultKeys: case RequiredUserAction::kFetchingTrustedVaultKeys:
case RequiredUserAction::kTrustedVaultKeyRequired: case RequiredUserAction::kTrustedVaultKeyRequired:
...@@ -557,9 +574,19 @@ void SyncServiceCrypto::OnCryptographerStateChanged( ...@@ -557,9 +574,19 @@ void SyncServiceCrypto::OnCryptographerStateChanged(
void SyncServiceCrypto::OnPassphraseTypeChanged(PassphraseType type, void SyncServiceCrypto::OnPassphraseTypeChanged(PassphraseType type,
base::Time passphrase_time) { base::Time passphrase_time) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(1) << "Passphrase type changed to " << PassphraseTypeToString(type); DVLOG(1) << "Passphrase type changed to " << PassphraseTypeToString(type);
state_.cached_passphrase_type = type; state_.cached_passphrase_type = type;
state_.cached_explicit_passphrase_time = passphrase_time; state_.cached_explicit_passphrase_time = passphrase_time;
// Clear recoverability degraded state in case a custom passphrase was set.
if (type != PassphraseType::kTrustedVaultPassphrase &&
state_.required_user_action ==
RequiredUserAction::kTrustedVaultRecoverabilityDegraded) {
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
}
notify_observers_.Run(); notify_observers_.Run();
} }
...@@ -597,6 +624,7 @@ void SyncServiceCrypto::OnTrustedVaultClientKeysChanged() { ...@@ -597,6 +624,7 @@ void SyncServiceCrypto::OnTrustedVaultClientKeysChanged() {
case RequiredUserAction::kNone: case RequiredUserAction::kNone:
case RequiredUserAction::kPassphraseRequiredForDecryption: case RequiredUserAction::kPassphraseRequiredForDecryption:
case RequiredUserAction::kPassphraseRequiredForEncryption: case RequiredUserAction::kPassphraseRequiredForEncryption:
case RequiredUserAction::kTrustedVaultRecoverabilityDegraded:
// If no trusted vault keys are required, there's nothing to do. If they // If no trusted vault keys are required, there's nothing to do. If they
// later are required, a fetch will be triggered in // later are required, a fetch will be triggered in
// OnTrustedVaultKeyRequired(). // OnTrustedVaultKeyRequired().
...@@ -739,8 +767,50 @@ void SyncServiceCrypto::UpdateRequiredUserActionAndNotify( ...@@ -739,8 +767,50 @@ void SyncServiceCrypto::UpdateRequiredUserActionAndNotify(
RequiredUserAction new_required_user_action) { RequiredUserAction new_required_user_action) {
DCHECK_NE(new_required_user_action, DCHECK_NE(new_required_user_action,
RequiredUserAction::kUnknownDuringInitialization); RequiredUserAction::kUnknownDuringInitialization);
if (state_.required_user_action == new_required_user_action) {
return;
}
state_.required_user_action = new_required_user_action; state_.required_user_action = new_required_user_action;
notify_required_user_action_changed_.Run(); notify_required_user_action_changed_.Run();
if (state_.required_user_action == RequiredUserAction::kNone &&
state_.cached_passphrase_type ==
PassphraseType::kTrustedVaultPassphrase &&
base::FeatureList::IsEnabled(
switches::kSyncSupportTrustedVaultPassphraseRecovery)) {
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;
}
// Transition from non-degraded to degraded recoverability.
if (is_recoverability_degraded &&
state_.required_user_action == RequiredUserAction::kNone) {
UpdateRequiredUserActionAndNotify(
RequiredUserAction::kTrustedVaultRecoverabilityDegraded);
notify_observers_.Run();
}
// Transition from degraded to non-degraded recoverability.
if (!is_recoverability_degraded &&
state_.required_user_action ==
RequiredUserAction::kTrustedVaultRecoverabilityDegraded) {
UpdateRequiredUserActionAndNotify(RequiredUserAction::kNone);
notify_observers_.Run();
}
} }
} // namespace syncer } // namespace syncer
...@@ -48,6 +48,7 @@ class SyncServiceCrypto : public SyncEncryptionHandler::Observer, ...@@ -48,6 +48,7 @@ class SyncServiceCrypto : public SyncEncryptionHandler::Observer,
bool IsPassphraseRequired() const; bool IsPassphraseRequired() const;
bool IsUsingSecondaryPassphrase() const; bool IsUsingSecondaryPassphrase() const;
bool IsTrustedVaultKeyRequired() const; bool IsTrustedVaultKeyRequired() const;
bool IsTrustedVaultRecoverabilityDegraded() const;
void EnableEncryptEverything(); void EnableEncryptEverything();
bool IsEncryptEverythingEnabled() const; bool IsEncryptEverythingEnabled() const;
void SetEncryptionPassphrase(const std::string& passphrase); void SetEncryptionPassphrase(const std::string& passphrase);
...@@ -107,6 +108,9 @@ class SyncServiceCrypto : public SyncEncryptionHandler::Observer, ...@@ -107,6 +108,9 @@ class SyncServiceCrypto : public SyncEncryptionHandler::Observer,
// via IsTrustedVaultKeyRequired() but there's an ongoing fetch that may // via IsTrustedVaultKeyRequired() but there's an ongoing fetch that may
// resolve the issue. // resolve the issue.
kTrustedVaultKeyRequiredButFetching, kTrustedVaultKeyRequiredButFetching,
// No keys are required locally but user action is recommended to improve
// recoverability.
kTrustedVaultRecoverabilityDegraded,
}; };
// Observer method invoked by TrustedVaultClient when its content changes. // Observer method invoked by TrustedVaultClient when its content changes.
...@@ -131,6 +135,10 @@ class SyncServiceCrypto : public SyncEncryptionHandler::Observer, ...@@ -131,6 +135,10 @@ class SyncServiceCrypto : public SyncEncryptionHandler::Observer,
void UpdateRequiredUserActionAndNotify( void UpdateRequiredUserActionAndNotify(
RequiredUserAction new_required_user_action); RequiredUserAction new_required_user_action);
// Completion callback function for
// TrustedVaultClient::GetIsRecoverabilityDegraded().
void GetIsRecoverabilityDegradedCompleted(bool is_recoverability_degraded);
// Calls SyncServiceBase::NotifyObservers(). Never null. // Calls SyncServiceBase::NotifyObservers(). Never null.
const base::RepeatingClosure notify_observers_; const base::RepeatingClosure notify_observers_;
......
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/mock_callback.h" #include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/account_info.h"
#include "components/sync/base/sync_prefs.h" #include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/trusted_vault_client.h" #include "components/sync/driver/trusted_vault_client.h"
#include "components/sync/engine/mock_sync_engine.h" #include "components/sync/engine/mock_sync_engine.h"
#include "components/sync/engine/sync_engine_switches.h"
#include "components/sync/nigori/nigori.h" #include "components/sync/nigori/nigori.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -130,6 +132,11 @@ class TestTrustedVaultClient : public TrustedVaultClient { ...@@ -130,6 +132,11 @@ class TestTrustedVaultClient : public TrustedVaultClient {
// Exposes the total number of calls to the server's RequestKeysFromServer(). // Exposes the total number of calls to the server's RequestKeysFromServer().
int server_request_count() const { return server_request_count_; } int server_request_count() const { return server_request_count_; }
// Exposes the total number of calls to GetIsRecoverabilityDegraded().
int get_is_recoverablity_degraded_call_count() const {
return get_is_recoverablity_degraded_call_count_;
}
// Mimics the completion of the next (FIFO) FetchKeys() request. // Mimics the completion of the next (FIFO) FetchKeys() request.
bool CompleteFetchKeysRequest() { bool CompleteFetchKeysRequest() {
if (pending_responses_.empty()) { if (pending_responses_.empty()) {
...@@ -142,6 +149,10 @@ class TestTrustedVaultClient : public TrustedVaultClient { ...@@ -142,6 +149,10 @@ class TestTrustedVaultClient : public TrustedVaultClient {
return true; return true;
} }
void SetIsRecoverabilityDegraded(bool is_recoverability_degraded) {
is_recoverability_degraded_ = is_recoverability_degraded;
}
// TrustedVaultClient implementation. // TrustedVaultClient implementation.
std::unique_ptr<Subscription> AddKeysChangedObserver( std::unique_ptr<Subscription> AddKeysChangedObserver(
const base::RepeatingClosure& cb) override { const base::RepeatingClosure& cb) override {
...@@ -219,6 +230,12 @@ class TestTrustedVaultClient : public TrustedVaultClient { ...@@ -219,6 +230,12 @@ class TestTrustedVaultClient : public TrustedVaultClient {
std::move(cb).Run(true); std::move(cb).Run(true);
} }
void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override {
++get_is_recoverablity_degraded_call_count_;
std::move(cb).Run(is_recoverability_degraded_);
}
private: private:
struct CachedKeysPerUser { struct CachedKeysPerUser {
bool marked_as_stale = false; bool marked_as_stale = false;
...@@ -231,8 +248,10 @@ class TestTrustedVaultClient : public TrustedVaultClient { ...@@ -231,8 +248,10 @@ class TestTrustedVaultClient : public TrustedVaultClient {
CallbackList observer_list_; CallbackList observer_list_;
int fetch_count_ = 0; int fetch_count_ = 0;
int keys_marked_as_stale_count_ = 0; int keys_marked_as_stale_count_ = 0;
int get_is_recoverablity_degraded_call_count_ = 0;
int server_request_count_ = 0; int server_request_count_ = 0;
std::list<base::OnceClosure> pending_responses_; std::list<base::OnceClosure> pending_responses_;
bool is_recoverability_degraded_ = false;
}; };
class SyncServiceCryptoTest : public testing::Test { class SyncServiceCryptoTest : public testing::Test {
...@@ -289,6 +308,7 @@ TEST_F(SyncServiceCryptoTest, ShouldRequireNoUserAction) { ...@@ -289,6 +308,7 @@ TEST_F(SyncServiceCryptoTest, ShouldRequireNoUserAction) {
EXPECT_FALSE(crypto_.IsPassphraseRequired()); EXPECT_FALSE(crypto_.IsPassphraseRequired());
EXPECT_FALSE(crypto_.IsTrustedVaultKeyRequired()); EXPECT_FALSE(crypto_.IsTrustedVaultKeyRequired());
EXPECT_TRUE(crypto_.IsTrustedVaultKeyRequiredStateKnown()); EXPECT_TRUE(crypto_.IsTrustedVaultKeyRequiredStateKnown());
EXPECT_FALSE(crypto_.IsTrustedVaultRecoverabilityDegraded());
} }
TEST_F(SyncServiceCryptoTest, ShouldSetUpNewCustomPassphrase) { TEST_F(SyncServiceCryptoTest, ShouldSetUpNewCustomPassphrase) {
...@@ -752,6 +772,93 @@ TEST_F( ...@@ -752,6 +772,93 @@ TEST_F(
EXPECT_THAT(trusted_vault_client_.fetch_count(), Eq(3)); EXPECT_THAT(trusted_vault_client_.fetch_count(), Eq(3));
} }
TEST_F(SyncServiceCryptoTest, ShouldNotGetRecoverabilityIfFeatureDisabled) {
trusted_vault_client_.SetIsRecoverabilityDegraded(true);
crypto_.OnPassphraseTypeChanged(PassphraseType::kTrustedVaultPassphrase,
base::Time::Now());
crypto_.SetSyncEngine(CoreAccountInfo(), &engine_);
ASSERT_THAT(crypto_.GetPassphraseType(),
Eq(PassphraseType::kTrustedVaultPassphrase));
ASSERT_TRUE(crypto_.IsTrustedVaultKeyRequiredStateKnown());
ASSERT_FALSE(crypto_.IsTrustedVaultKeyRequired());
EXPECT_THAT(trusted_vault_client_.get_is_recoverablity_degraded_call_count(),
Eq(0));
EXPECT_FALSE(crypto_.IsTrustedVaultRecoverabilityDegraded());
}
TEST_F(SyncServiceCryptoTest, ShouldNotReportDegradedRecoverability) {
base::test::ScopedFeatureList override_features;
override_features.InitAndEnableFeature(
switches::kSyncSupportTrustedVaultPassphraseRecovery);
trusted_vault_client_.SetIsRecoverabilityDegraded(false);
crypto_.OnPassphraseTypeChanged(PassphraseType::kTrustedVaultPassphrase,
base::Time::Now());
crypto_.SetSyncEngine(CoreAccountInfo(), &engine_);
ASSERT_THAT(crypto_.GetPassphraseType(),
Eq(PassphraseType::kTrustedVaultPassphrase));
ASSERT_TRUE(crypto_.IsTrustedVaultKeyRequiredStateKnown());
ASSERT_FALSE(crypto_.IsTrustedVaultKeyRequired());
EXPECT_FALSE(crypto_.IsTrustedVaultRecoverabilityDegraded());
}
TEST_F(SyncServiceCryptoTest, ShouldReportDegradedRecoverability) {
base::test::ScopedFeatureList override_features;
override_features.InitAndEnableFeature(
switches::kSyncSupportTrustedVaultPassphraseRecovery);
trusted_vault_client_.SetIsRecoverabilityDegraded(true);
crypto_.OnPassphraseTypeChanged(PassphraseType::kTrustedVaultPassphrase,
base::Time::Now());
crypto_.SetSyncEngine(CoreAccountInfo(), &engine_);
ASSERT_THAT(crypto_.GetPassphraseType(),
Eq(PassphraseType::kTrustedVaultPassphrase));
ASSERT_TRUE(crypto_.IsTrustedVaultKeyRequiredStateKnown());
ASSERT_FALSE(crypto_.IsTrustedVaultKeyRequired());
EXPECT_TRUE(crypto_.IsTrustedVaultRecoverabilityDegraded());
}
TEST_F(SyncServiceCryptoTest,
ShouldClearDegradedRecoverabilityIfCustomPassphraseIsSet) {
const std::string kTestPassphrase = "somepassphrase";
base::test::ScopedFeatureList override_features;
override_features.InitAndEnableFeature(
switches::kSyncSupportTrustedVaultPassphraseRecovery);
// Mimic a browser startup in |kTrustedVaultPassphrase| with no additional
// keys required and degraded recoverability state.
trusted_vault_client_.SetIsRecoverabilityDegraded(true);
crypto_.OnPassphraseTypeChanged(PassphraseType::kTrustedVaultPassphrase,
base::Time::Now());
crypto_.SetSyncEngine(CoreAccountInfo(), &engine_);
ASSERT_THAT(crypto_.GetPassphraseType(),
Eq(PassphraseType::kTrustedVaultPassphrase));
ASSERT_TRUE(crypto_.IsTrustedVaultKeyRequiredStateKnown());
ASSERT_FALSE(crypto_.IsTrustedVaultKeyRequired());
ASSERT_FALSE(crypto_.IsPassphraseRequired());
ASSERT_TRUE(crypto_.IsTrustedVaultRecoverabilityDegraded());
// Mimic the user setting up a new custom passphrase.
crypto_.SetEncryptionPassphrase(kTestPassphrase);
// Mimic completion of the procedure in the sync engine.
EXPECT_CALL(reconfigure_cb_, Run(CONFIGURE_REASON_CRYPTO));
EXPECT_CALL(notify_observers_cb_, Run());
crypto_.OnPassphraseTypeChanged(PassphraseType::kCustomPassphrase,
base::Time::Now());
crypto_.OnPassphraseAccepted();
ASSERT_THAT(crypto_.GetPassphraseType(),
Eq(PassphraseType::kCustomPassphrase));
// Recoverability should no longer be considered degraded.
EXPECT_FALSE(crypto_.IsTrustedVaultRecoverabilityDegraded());
}
} // namespace } // namespace
} // namespace syncer } // namespace syncer
...@@ -109,8 +109,11 @@ class SyncUserSettings { ...@@ -109,8 +109,11 @@ class SyncUserSettings {
// encrypted data types. // encrypted data types.
virtual bool IsTrustedVaultKeyRequired() const = 0; virtual bool IsTrustedVaultKeyRequired() const = 0;
// Whether trusted vault keys are required for encryption or decryption to // Whether trusted vault keys are required for encryption or decryption to
// proceed for any currently enabled data type. // proceed for currently enabled data types.
virtual bool IsTrustedVaultKeyRequiredForPreferredDataTypes() const = 0; virtual bool IsTrustedVaultKeyRequiredForPreferredDataTypes() const = 0;
// Whether recoverability of the trusted vault keys is degraded and user
// action is required, affecting currently enabled data types.
virtual bool IsTrustedVaultRecoverabilityDegraded() const = 0;
// Whether a "secondary" passphrase is in use (aka explicit passphrase), which // Whether a "secondary" passphrase is in use (aka explicit passphrase), which
// means either a custom or a frozen implicit passphrase. // means either a custom or a frozen implicit passphrase.
virtual bool IsUsingSecondaryPassphrase() const = 0; virtual bool IsUsingSecondaryPassphrase() const = 0;
......
...@@ -198,6 +198,13 @@ bool SyncUserSettingsImpl::IsTrustedVaultKeyRequiredForPreferredDataTypes() ...@@ -198,6 +198,13 @@ bool SyncUserSettingsImpl::IsTrustedVaultKeyRequiredForPreferredDataTypes()
return IsEncryptedDatatypeEnabled() && crypto_->IsTrustedVaultKeyRequired(); return IsEncryptedDatatypeEnabled() && crypto_->IsTrustedVaultKeyRequired();
} }
bool SyncUserSettingsImpl::IsTrustedVaultRecoverabilityDegraded() const {
// TODO(crbug.com/1081649): This should verify that at least one sync entity
// is affected.
return IsEncryptedDatatypeEnabled() &&
crypto_->IsTrustedVaultRecoverabilityDegraded();
}
bool SyncUserSettingsImpl::IsUsingSecondaryPassphrase() const { bool SyncUserSettingsImpl::IsUsingSecondaryPassphrase() const {
return crypto_->IsUsingSecondaryPassphrase(); return crypto_->IsUsingSecondaryPassphrase();
} }
......
...@@ -66,6 +66,7 @@ class SyncUserSettingsImpl : public SyncUserSettings { ...@@ -66,6 +66,7 @@ class SyncUserSettingsImpl : public SyncUserSettings {
bool IsPassphraseRequiredForPreferredDataTypes() const override; bool IsPassphraseRequiredForPreferredDataTypes() const override;
bool IsTrustedVaultKeyRequired() const override; bool IsTrustedVaultKeyRequired() const override;
bool IsTrustedVaultKeyRequiredForPreferredDataTypes() const override; bool IsTrustedVaultKeyRequiredForPreferredDataTypes() const override;
bool IsTrustedVaultRecoverabilityDegraded() const override;
bool IsUsingSecondaryPassphrase() const override; bool IsUsingSecondaryPassphrase() const override;
base::Time GetExplicitPassphraseTime() const override; base::Time GetExplicitPassphraseTime() const override;
PassphraseType GetPassphraseType() const override; PassphraseType GetPassphraseType() const override;
......
...@@ -51,6 +51,7 @@ class SyncUserSettingsMock : public SyncUserSettings { ...@@ -51,6 +51,7 @@ class SyncUserSettingsMock : public SyncUserSettings {
MOCK_CONST_METHOD0(IsPassphraseRequiredForPreferredDataTypes, bool()); MOCK_CONST_METHOD0(IsPassphraseRequiredForPreferredDataTypes, bool());
MOCK_CONST_METHOD0(IsTrustedVaultKeyRequired, bool()); MOCK_CONST_METHOD0(IsTrustedVaultKeyRequired, bool());
MOCK_CONST_METHOD0(IsTrustedVaultKeyRequiredForPreferredDataTypes, bool()); MOCK_CONST_METHOD0(IsTrustedVaultKeyRequiredForPreferredDataTypes, bool());
MOCK_CONST_METHOD0(IsTrustedVaultRecoverabilityDegraded, bool());
MOCK_CONST_METHOD0(IsUsingSecondaryPassphrase, bool()); MOCK_CONST_METHOD0(IsUsingSecondaryPassphrase, bool());
MOCK_CONST_METHOD0(GetExplicitPassphraseTime, base::Time()); MOCK_CONST_METHOD0(GetExplicitPassphraseTime, base::Time());
MOCK_CONST_METHOD0(GetPassphraseType, PassphraseType()); MOCK_CONST_METHOD0(GetPassphraseType, PassphraseType());
......
...@@ -179,6 +179,10 @@ bool TestSyncUserSettings::IsTrustedVaultKeyRequiredForPreferredDataTypes() ...@@ -179,6 +179,10 @@ bool TestSyncUserSettings::IsTrustedVaultKeyRequiredForPreferredDataTypes()
return trusted_vault_key_required_for_preferred_data_types_; return trusted_vault_key_required_for_preferred_data_types_;
} }
bool TestSyncUserSettings::IsTrustedVaultRecoverabilityDegraded() const {
return false;
}
bool TestSyncUserSettings::IsUsingSecondaryPassphrase() const { bool TestSyncUserSettings::IsUsingSecondaryPassphrase() const {
return using_secondary_passphrase_; return using_secondary_passphrase_;
} }
......
...@@ -55,6 +55,7 @@ class TestSyncUserSettings : public SyncUserSettings { ...@@ -55,6 +55,7 @@ class TestSyncUserSettings : public SyncUserSettings {
bool IsPassphraseRequiredForPreferredDataTypes() const override; bool IsPassphraseRequiredForPreferredDataTypes() const override;
bool IsTrustedVaultKeyRequired() const override; bool IsTrustedVaultKeyRequired() const override;
bool IsTrustedVaultKeyRequiredForPreferredDataTypes() const override; bool IsTrustedVaultKeyRequiredForPreferredDataTypes() const override;
bool IsTrustedVaultRecoverabilityDegraded() const override;
bool IsUsingSecondaryPassphrase() const override; bool IsUsingSecondaryPassphrase() const override;
base::Time GetExplicitPassphraseTime() const override; base::Time GetExplicitPassphraseTime() const override;
PassphraseType GetPassphraseType() const override; PassphraseType GetPassphraseType() const override;
......
...@@ -66,6 +66,14 @@ class TrustedVaultClient { ...@@ -66,6 +66,14 @@ class TrustedVaultClient {
// when accounts cookies deleted by the user action. // when accounts cookies deleted by the user action.
virtual void RemoveAllStoredKeys() = 0; virtual void RemoveAllStoredKeys() = 0;
// Returns whether recoverability of the keys is degraded and user action is
// required to add a new method. This may be called frequently and
// implementations are responsible for implementing caching and possibly
// throttling.
virtual void GetIsRecoverabilityDegraded(
const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) = 0;
private: private:
DISALLOW_COPY_AND_ASSIGN(TrustedVaultClient); DISALLOW_COPY_AND_ASSIGN(TrustedVaultClient);
}; };
......
...@@ -20,6 +20,10 @@ const base::Feature kSyncUseScryptForNewCustomPassphrases{ ...@@ -20,6 +20,10 @@ const base::Feature kSyncUseScryptForNewCustomPassphrases{
const base::Feature kSyncSupportTrustedVaultPassphrase{ const base::Feature kSyncSupportTrustedVaultPassphrase{
"SyncSupportTrustedVaultPassphrase", base::FEATURE_ENABLED_BY_DEFAULT}; "SyncSupportTrustedVaultPassphrase", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kSyncSupportTrustedVaultPassphraseRecovery{
"SyncSupportTrustedVaultPassphraseRecovery",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kSyncTriggerFullKeystoreMigration{ const base::Feature kSyncTriggerFullKeystoreMigration{
"SyncTriggerFullKeystoreMigration", base::FEATURE_ENABLED_BY_DEFAULT}; "SyncTriggerFullKeystoreMigration", base::FEATURE_ENABLED_BY_DEFAULT};
......
...@@ -12,6 +12,7 @@ namespace switches { ...@@ -12,6 +12,7 @@ namespace switches {
extern const base::Feature kSyncResetPollIntervalOnStart; extern const base::Feature kSyncResetPollIntervalOnStart;
extern const base::Feature kSyncUseScryptForNewCustomPassphrases; extern const base::Feature kSyncUseScryptForNewCustomPassphrases;
extern const base::Feature kSyncSupportTrustedVaultPassphrase; extern const base::Feature kSyncSupportTrustedVaultPassphrase;
extern const base::Feature kSyncSupportTrustedVaultPassphraseRecovery;
extern const base::Feature kSyncTriggerFullKeystoreMigration; extern const base::Feature kSyncTriggerFullKeystoreMigration;
} // namespace switches } // namespace switches
......
...@@ -77,6 +77,14 @@ void StandaloneTrustedVaultClient::MarkKeysAsStale( ...@@ -77,6 +77,14 @@ void StandaloneTrustedVaultClient::MarkKeysAsStale(
std::move(cb).Run(false); std::move(cb).Run(false);
} }
void StandaloneTrustedVaultClient::GetIsRecoverabilityDegraded(
const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) {
// TODO(crbug.com/1081649): Implement logic.
NOTIMPLEMENTED();
std::move(cb).Run(is_recoverability_degraded_for_testing_);
}
void StandaloneTrustedVaultClient::WaitForFlushForTesting( void StandaloneTrustedVaultClient::WaitForFlushForTesting(
base::OnceClosure cb) const { base::OnceClosure cb) const {
backend_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(), backend_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
...@@ -99,4 +107,8 @@ bool StandaloneTrustedVaultClient::IsInitializationTriggeredForTesting() const { ...@@ -99,4 +107,8 @@ bool StandaloneTrustedVaultClient::IsInitializationTriggeredForTesting() const {
return backend_ != nullptr; return backend_ != nullptr;
} }
void StandaloneTrustedVaultClient::SetRecoverabilityDegradedForTesting() {
is_recoverability_degraded_for_testing_ = true;
}
} // namespace syncer } // namespace syncer
...@@ -48,10 +48,13 @@ class StandaloneTrustedVaultClient : public TrustedVaultClient { ...@@ -48,10 +48,13 @@ class StandaloneTrustedVaultClient : public TrustedVaultClient {
void RemoveAllStoredKeys() override; void RemoveAllStoredKeys() override;
void MarkKeysAsStale(const CoreAccountInfo& account_info, void MarkKeysAsStale(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override; base::OnceCallback<void(bool)> cb) override;
void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb) override;
// Runs |cb| when all requests have completed. // Runs |cb| when all requests have completed.
void WaitForFlushForTesting(base::OnceClosure cb) const; void WaitForFlushForTesting(base::OnceClosure cb) const;
bool IsInitializationTriggeredForTesting() const; bool IsInitializationTriggeredForTesting() const;
void SetRecoverabilityDegradedForTesting();
private: private:
void TriggerLazyInitializationIfNeeded(); void TriggerLazyInitializationIfNeeded();
...@@ -64,6 +67,8 @@ class StandaloneTrustedVaultClient : public TrustedVaultClient { ...@@ -64,6 +67,8 @@ class StandaloneTrustedVaultClient : public TrustedVaultClient {
// |backend_| constructed lazily in the UI thread, used in // |backend_| constructed lazily in the UI thread, used in
// |backend_task_runner_| and destroyed (refcounted) on any thread. // |backend_task_runner_| and destroyed (refcounted) on any thread.
scoped_refptr<StandaloneTrustedVaultBackend> backend_; scoped_refptr<StandaloneTrustedVaultBackend> backend_;
bool is_recoverability_degraded_for_testing_ = false;
}; };
} // namespace syncer } // namespace syncer
......
...@@ -27,6 +27,9 @@ class IOSTrustedVaultClient : public syncer::TrustedVaultClient { ...@@ -27,6 +27,9 @@ class IOSTrustedVaultClient : public syncer::TrustedVaultClient {
void RemoveAllStoredKeys() override; void RemoveAllStoredKeys() override;
void MarkKeysAsStale(const CoreAccountInfo& account_info, void MarkKeysAsStale(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> callback) override; base::OnceCallback<void(bool)> callback) override;
void GetIsRecoverabilityDegraded(
const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> callback) override;
// Not copyable or movable // Not copyable or movable
IOSTrustedVaultClient(const IOSTrustedVaultClient&) = delete; IOSTrustedVaultClient(const IOSTrustedVaultClient&) = delete;
......
...@@ -62,6 +62,13 @@ void IOSTrustedVaultClient::RemoveAllStoredKeys() { ...@@ -62,6 +62,13 @@ void IOSTrustedVaultClient::RemoveAllStoredKeys() {
void IOSTrustedVaultClient::MarkKeysAsStale( void IOSTrustedVaultClient::MarkKeysAsStale(
const CoreAccountInfo& account_info, const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> callback) { base::OnceCallback<void(bool)> callback) {
// TODO(crbug.com/1019685): needs implementation. // TODO(crbug.com/1100278): Needs implementation.
std::move(callback).Run(false);
}
void IOSTrustedVaultClient::GetIsRecoverabilityDegraded(
const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> callback) {
// TODO(crbug.com/1100278): Needs implementation.
std::move(callback).Run(false); std::move(callback).Run(false);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment