chromium/chrome/browser/ui/views/webauthn/authenticator_touch_id_view.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/ui/views/webauthn/authenticator_touch_id_view.h"

#include <memory>
#include <optional>

#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/webauthn/authenticator_common_views.h"
#include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h"
#include "chrome/browser/ui/views/webauthn/mac_authentication_view.h"
#include "chrome/browser/ui/views/webauthn/passkey_detail_view.h"
#include "chrome/browser/ui/webauthn/sheet_models.h"
#include "chrome/grit/generated_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "crypto/scoped_lacontext.h"
#include "device/fido/fido_constants.h"
#include "device/fido/mac/util.h"
#include "device/fido/strings/grit/fido_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/color/color_id.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/view.h"

namespace {
constexpr int kVerticalPadding = 20;

// The size if the lock icon that replaces the Touch ID prompt when locked
// (square).
constexpr int kLockIconSize = 64;
}  // namespace

AuthenticatorTouchIdView::AuthenticatorTouchIdView(
    std::unique_ptr<AuthenticatorTouchIdSheetModel> sheet_model)
    : AuthenticatorRequestSheetView(std::move(sheet_model)) {}

AuthenticatorTouchIdView::~AuthenticatorTouchIdView() = default;

std::unique_ptr<views::View>
AuthenticatorTouchIdView::BuildStepSpecificHeader() {
  return CreateGpmIconWithLabel();
}

std::pair<std::unique_ptr<views::View>, AuthenticatorTouchIdView::AutoFocus>
AuthenticatorTouchIdView::BuildStepSpecificContent() {
  auto container = std::make_unique<views::BoxLayoutView>();
  auto* dialog_model =
      static_cast<AuthenticatorTouchIdSheetModel*>(model())->dialog_model();
  bool is_get_assertion =
      dialog_model->request_type == device::FidoRequestType::kGetAssertion;
  container->SetOrientation(views::BoxLayout::Orientation::kVertical);
  container->SetBetweenChildSpacing(kVerticalPadding);
  container->AddChildView(CreatePasskeyWithUsernameLabel(base::UTF8ToUTF16(
      (is_get_assertion ? dialog_model->preselected_cred->user.name
                        : dialog_model->user_entity.name)
          .value_or(""))));
  if (device::fido::mac::DeviceHasBiometricsAvailable()) {
    container->AddChildView(std::make_unique<MacAuthenticationView>(
        base::BindOnce(&AuthenticatorTouchIdView::OnTouchIDComplete,
                       base::Unretained(this)),
        l10n_util::GetStringFUTF16(
            IDS_WEBAUTHN_TOUCH_ID_PROMPT_REASON,
            base::UTF8ToUTF16(dialog_model->relying_party_id))));
    container->AddChildView(std::make_unique<views::Label>(
        l10n_util::GetStringUTF16(IDS_WEBAUTHN_TOUCH_ID_CONTINUE)));
  } else {
    container->AddChildView(
        std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon(
            vector_icons::kLockIcon, ui::kColorMenuIcon, kLockIconSize)));
    container->AddChildView(std::make_unique<views::Label>(
        l10n_util::GetStringUTF16(IDS_WEBAUTHN_TOUCH_ID_LOCKED)));
  }
  return {std::move(container), AutoFocus::kNo};
}

void AuthenticatorTouchIdView::OnTouchIDComplete(
    std::optional<crypto::ScopedLAContext> lacontext) {
  static_cast<AuthenticatorTouchIdSheetModel*>(model())->OnTouchIDSensorTapped(
      std::move(lacontext));
}