910e62b5创建于 1月15日历史提交
// 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/ash/auth/active_session_fingerprint_client_impl.h"

#include <memory>

#include "ash/constants/ash_pref_names.h"
#include "ash/public/cpp/ash_public_export.h"
#include "ash/public/cpp/auth/active_session_auth_controller.h"
#include "ash/public/cpp/auth/active_session_fingerprint_client.h"
#include "ash/public/cpp/login_types.h"
#include "ash/shell.h"
#include "base/check.h"
#include "base/check_is_test.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/values.h"
#include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
#include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
#include "chromeos/ash/components/login/auth/public/auth_callbacks.h"
#include "chromeos/ash/components/login/auth/public/user_context.h"
#include "chromeos/ash/components/osauth/public/request/auth_request.h"
#include "components/account_id/account_id.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"

namespace ash {

namespace {

const char kFactorsOptionAll[] = "all";
const char kFactorsOptionFingerprint[] = "FINGERPRINT";

}  // namespace

ActiveSessionFingerprintClientImpl::ActiveSessionFingerprintClientImpl()
    : auth_performer_(UserDataAuthClient::Get()) {
  if (Shell::HasInstance()) {
    Shell::Get()->active_session_auth_controller()->SetFingerprintClient(this);
    shell_observation_.Observe(ash::Shell::Get());
  } else {
    CHECK_IS_TEST();
  }
}

ActiveSessionFingerprintClientImpl::~ActiveSessionFingerprintClientImpl() {
  if (Shell::HasInstance()) {
    Shell::Get()->active_session_auth_controller()->SetFingerprintClient(
        nullptr);
  }
}

void ActiveSessionFingerprintClientImpl::OnShellDestroying() {
  Shell::Get()->active_session_auth_controller()->SetFingerprintClient(nullptr);
  shell_observation_.Reset();
}

bool ActiveSessionFingerprintClientImpl::IsFingerprintAvailable(
    AuthRequest::Reason reason,
    const AccountId& account_id) {
  auto* profile = ProfileHelper::Get()->GetProfileByAccountId(account_id);

  CHECK(profile);

  auto* pref_service = profile->GetPrefs();

  if (!pref_service) {
    return false;
  }

  if (profile != ProfileManager::GetPrimaryUserProfile()) {
    return false;
  }

  bool has_record =
      pref_service->GetInteger(prefs::kQuickUnlockFingerprintRecord);

  if (!has_record) {
    return false;
  }

  switch (reason) {
    case AuthRequest::Reason::kSettings:
      return false;
    case AuthRequest::Reason::kPasswordManager: {
      if (pref_service->GetBoolean(
              password_manager::prefs::kBiometricAuthenticationBeforeFilling)) {
        const base::Value::List& factors =
            pref_service->GetList(prefs::kQuickUnlockModeAllowlist);
        if (base::Contains(factors, base::Value(kFactorsOptionAll)) ||
            base::Contains(factors, base::Value(kFactorsOptionFingerprint))) {
          return true;
        }
      }
      return false;
    }
    case AuthRequest::Reason::kWebAuthN: {
      const base::Value::List& factors =
          pref_service->GetList(prefs::kWebAuthnFactors);
      if (base::Contains(factors, base::Value(kFactorsOptionAll)) ||
          base::Contains(factors, base::Value(kFactorsOptionFingerprint))) {
        return true;
      }
      return false;
    }
  }
  NOTREACHED();
}

void ActiveSessionFingerprintClientImpl::PrepareFingerprintAuth(
    std::unique_ptr<UserContext> user_context,
    AuthOperationCallback auth_ready_callback,
    ActiveSessionFingerprintScanCallback on_scan_callback) {
  CHECK(on_scan_callback_.is_null());
  CHECK(!on_scan_callback.is_null());
  on_scan_callback_ = std::move(on_scan_callback);
  auth_performer_.PrepareAuthFactor(
      std::move(user_context), cryptohome::AuthFactorType::kLegacyFingerprint,
      base::BindOnce(
          &ActiveSessionFingerprintClientImpl::OnPrepareFingerprintAuth,
          weak_factory_.GetWeakPtr(), std::move(auth_ready_callback)));
}

void ActiveSessionFingerprintClientImpl::OnPrepareFingerprintAuth(
    AuthOperationCallback auth_ready_callback,
    std::unique_ptr<UserContext> user_context,
    std::optional<AuthenticationError> auth_error) {
  if (auth_error.has_value()) {
    LOG(ERROR) << "PrepareFingerprintAuth failed.";
    on_scan_callback_.Reset();
  }
  UserDataAuthClient::Get()->AddFingerprintAuthObserver(this);
  std::move(auth_ready_callback).Run(std::move(user_context), auth_error);
}

void ActiveSessionFingerprintClientImpl::TerminateFingerprintAuth(
    std::unique_ptr<UserContext> user_context,
    AuthOperationCallback callback) {
  UserDataAuthClient::Get()->RemoveFingerprintAuthObserver(this);
  on_scan_callback_.Reset();
  auth_performer_.TerminateAuthFactor(
      std::move(user_context), cryptohome::AuthFactorType::kLegacyFingerprint,
      std::move(callback));
}

void ActiveSessionFingerprintClientImpl::OnFingerprintScan(
    const ::user_data_auth::FingerprintScanResult& result) {
  if (on_scan_callback_.is_null()) {
    return;
  }

  FingerprintAuthScanResult state;
  switch (result) {
    case ::user_data_auth::FingerprintScanResult::
        FINGERPRINT_SCAN_RESULT_SUCCESS:
      state = ash::FingerprintAuthScanResult::kSuccess;
      break;
    case ::user_data_auth::FingerprintScanResult::FINGERPRINT_SCAN_RESULT_RETRY:
      state = ash::FingerprintAuthScanResult::kFailed;
      break;
    case ::user_data_auth::FingerprintScanResult::
        FINGERPRINT_SCAN_RESULT_LOCKOUT:
      state = ash::FingerprintAuthScanResult::kTooManyAttempts;
      break;
    case ::user_data_auth::FingerprintScanResult::
        FINGERPRINT_SCAN_RESULT_FATAL_ERROR:
      state = ash::FingerprintAuthScanResult::kFatalError;
      break;
    default:  // The remaining states are for enrollment.
      NOTREACHED();
  }
  on_scan_callback_.Run(state);
}

void ActiveSessionFingerprintClientImpl::OnEnrollScanDone(
    const ::user_data_auth::FingerprintScanResult& result,
    bool is_complete,
    int percent_complete) {
  CHECK(on_scan_callback_.is_null());
}

}  // namespace ash