chromium/chrome/browser/password_manager/android/password_store_backend_migration_decorator.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/password_manager/android/password_store_backend_migration_decorator.h"

#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/sync/model/proxy_data_type_controller_delegate.h"
#include "components/sync/service/sync_service.h"

namespace password_manager {

PasswordStoreBackendMigrationDecorator::PasswordStoreBackendMigrationDecorator(
    std::unique_ptr<PasswordStoreBackend> built_in_backend,
    std::unique_ptr<PasswordStoreBackend> android_backend,
    PrefService* prefs)
    : built_in_backend_(std::move(built_in_backend)),
      android_backend_(std::move(android_backend)),
      prefs_(prefs) {
  CHECK(built_in_backend_);
  CHECK(android_backend_);
  migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
      built_in_backend_.get(), android_backend_.get(), prefs_);
}

PasswordStoreBackendMigrationDecorator::
    ~PasswordStoreBackendMigrationDecorator() = default;

void PasswordStoreBackendMigrationDecorator::InitBackend(
    AffiliatedMatchHelper* affiliated_match_helper,
    RemoteChangesReceived remote_form_changes_received,
    base::RepeatingClosure sync_enabled_or_disabled_cb,
    base::OnceCallback<void(bool)> completion) {
  base::RepeatingCallback<void(bool)> pending_initialization_calls =
      base::BarrierCallback<bool>(
          /*num_callbacks=*/2,
          base::BindOnce([](const std::vector<bool>& results) {
            return base::ranges::all_of(results, std::identity());
          }).Then(std::move(completion)));
  auto remote_changes_callback = base::BindRepeating(
      &PasswordStoreBackendMigrationDecorator::OnRemoteFormChangesReceived,
      weak_ptr_factory_.GetWeakPtr(), remote_form_changes_received);

  built_in_backend_->InitBackend(
      affiliated_match_helper,
      base::BindRepeating(remote_changes_callback,
                          built_in_backend_->AsWeakPtr()),
      std::move(sync_enabled_or_disabled_cb), pending_initialization_calls);
  android_backend_->InitBackend(
      /*affiliated_match_helper=*/nullptr,
      base::BindRepeating(remote_changes_callback,
                          android_backend_->AsWeakPtr()),
      base::NullCallback(), pending_initialization_calls);

  // Post delayed task to start migration of local passwords to avoid extra load
  // on start-up.

  metrics_util::LogLocalPwdMigrationProgressState(
      metrics_util::LocalPwdMigrationProgressState::kScheduled);
  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::
                         StartMigrationOfLocalPasswords,
                     migrator_->GetWeakPtr()),
      kLocalPasswordsMigrationToAndroidBackendDelay);
}

void PasswordStoreBackendMigrationDecorator::Shutdown(
    base::OnceClosure shutdown_completed) {
  weak_ptr_factory_.InvalidateWeakPtrs();
  migrator_.reset();

  auto shutdown_closure =
      base::BarrierClosure(2, std::move(shutdown_completed));
  built_in_backend_->Shutdown(
      base::BindOnce(shutdown_closure)
          .Then(base::OnceClosure(
              base::DoNothingWithBoundArgs(std::move(built_in_backend_)))));
  android_backend_->Shutdown(
      base::BindOnce(shutdown_closure)
          .Then(base::OnceClosure(
              base::DoNothingWithBoundArgs(std::move(android_backend_)))));
}

bool PasswordStoreBackendMigrationDecorator::IsAbleToSavePasswords() {
  // Suppress saving while the migration of local passwords is ongoing, to avoid
  // the migration "forgetting" any new passwords.
  return active_backend()->IsAbleToSavePasswords() &&
         !(migrator_ && migrator_->migration_in_progress());
}

void PasswordStoreBackendMigrationDecorator::GetAllLoginsAsync(
    LoginsOrErrorReply callback) {
  active_backend()->GetAllLoginsAsync(std::move(callback));
}

void PasswordStoreBackendMigrationDecorator::
    GetAllLoginsWithAffiliationAndBrandingAsync(LoginsOrErrorReply callback) {
  active_backend()->GetAllLoginsWithAffiliationAndBrandingAsync(
      std::move(callback));
}

void PasswordStoreBackendMigrationDecorator::GetAutofillableLoginsAsync(
    LoginsOrErrorReply callback) {
  active_backend()->GetAutofillableLoginsAsync(std::move(callback));
}

void PasswordStoreBackendMigrationDecorator::GetAllLoginsForAccountAsync(
    std::string account,
    LoginsOrErrorReply callback) {
  NOTREACHED();
}

void PasswordStoreBackendMigrationDecorator::FillMatchingLoginsAsync(
    LoginsOrErrorReply callback,
    bool include_psl,
    const std::vector<PasswordFormDigest>& forms) {
  active_backend()->FillMatchingLoginsAsync(std::move(callback), include_psl,
                                            forms);
}

void PasswordStoreBackendMigrationDecorator::GetGroupedMatchingLoginsAsync(
    const PasswordFormDigest& form_digest,
    LoginsOrErrorReply callback) {
  active_backend()->GetGroupedMatchingLoginsAsync(std::move(form_digest),
                                                  std::move(callback));
}

void PasswordStoreBackendMigrationDecorator::AddLoginAsync(
    const PasswordForm& form,
    PasswordChangesOrErrorReply callback) {
  active_backend()->AddLoginAsync(form, std::move(callback));
}

void PasswordStoreBackendMigrationDecorator::UpdateLoginAsync(
    const PasswordForm& form,
    PasswordChangesOrErrorReply callback) {
  active_backend()->UpdateLoginAsync(form, std::move(callback));
}

void PasswordStoreBackendMigrationDecorator::RemoveLoginAsync(
    const base::Location& location,
    const PasswordForm& form,
    PasswordChangesOrErrorReply callback) {
  active_backend()->RemoveLoginAsync(location, form, std::move(callback));
  if (UsesSplitStoresAndUPMForLocal(prefs_)) {
    built_in_backend_->RemoveLoginAsync(location, form, base::DoNothing());
  }
}

void PasswordStoreBackendMigrationDecorator::RemoveLoginsByURLAndTimeAsync(
    const base::Location& location,
    const base::RepeatingCallback<bool(const GURL&)>& url_filter,
    base::Time delete_begin,
    base::Time delete_end,
    base::OnceCallback<void(bool)> sync_completion,
    PasswordChangesOrErrorReply callback) {
  active_backend()->RemoveLoginsByURLAndTimeAsync(
      location, url_filter, delete_begin, delete_end,
      std::move(sync_completion), std::move(callback));
  if (UsesSplitStoresAndUPMForLocal(prefs_)) {
    built_in_backend_->RemoveLoginsByURLAndTimeAsync(
        location, url_filter, delete_begin, delete_end, base::NullCallback(),
        base::DoNothing());
  }
}

void PasswordStoreBackendMigrationDecorator::RemoveLoginsCreatedBetweenAsync(
    const base::Location& location,
    base::Time delete_begin,
    base::Time delete_end,
    PasswordChangesOrErrorReply callback) {
  active_backend()->RemoveLoginsCreatedBetweenAsync(
      location, delete_begin, delete_end, std::move(callback));
  if (UsesSplitStoresAndUPMForLocal(prefs_)) {
    built_in_backend_->RemoveLoginsCreatedBetweenAsync(
        location, delete_begin, delete_end, base::DoNothing());
  }
}

void PasswordStoreBackendMigrationDecorator::DisableAutoSignInForOriginsAsync(
    const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
    base::OnceClosure completion) {
  active_backend()->DisableAutoSignInForOriginsAsync(origin_filter,
                                                     std::move(completion));
}

SmartBubbleStatsStore*
PasswordStoreBackendMigrationDecorator::GetSmartBubbleStatsStore() {
  return nullptr;
}

std::unique_ptr<syncer::DataTypeControllerDelegate>
PasswordStoreBackendMigrationDecorator::CreateSyncControllerDelegate() {
  return built_in_backend_->CreateSyncControllerDelegate();
}

void PasswordStoreBackendMigrationDecorator::OnSyncServiceInitialized(
    syncer::SyncService* sync_service) {
  // TODO: b/323880741 - make sure `migrator_` doesn't require `sync_service`
  // for local password migration.
  if (migrator_) {
    migrator_->OnSyncServiceInitialized(sync_service);
  }
}

void PasswordStoreBackendMigrationDecorator::
    RecordAddLoginAsyncCalledFromTheStore() {
  active_backend()->RecordAddLoginAsyncCalledFromTheStore();
}

void PasswordStoreBackendMigrationDecorator::
    RecordUpdateLoginAsyncCalledFromTheStore() {
  active_backend()->RecordUpdateLoginAsyncCalledFromTheStore();
}

base::WeakPtr<PasswordStoreBackend>
PasswordStoreBackendMigrationDecorator::AsWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

void PasswordStoreBackendMigrationDecorator::OnRemoteFormChangesReceived(
    RemoteChangesReceived remote_form_changes_received,
    base::WeakPtr<PasswordStoreBackend> from_backend,
    std::optional<PasswordStoreChangeList> changes) {
  if (from_backend && from_backend.get() == active_backend()) {
    remote_form_changes_received.Run(std::move(changes));
  }
}

PasswordStoreBackend* PasswordStoreBackendMigrationDecorator::active_backend() {
  return UsesSplitStoresAndUPMForLocal(prefs_) ? android_backend_.get()
                                               : built_in_backend_.get();
}

}  // namespace password_manager