Commit ff1335d9 authored by Balazs Engedy's avatar Balazs Engedy Committed by Commit Bot

WebAuthn: Add pop-up menu for choosing other transports.

Bug: 847985
Change-Id: I2ae8ec26a2c01e2ffd1b1527cad0387c1e90f389
Reviewed-on: https://chromium-review.googlesource.com/1187104
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarJun Choi <hongjunchoi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585851}
parent 7c4fa8bc
...@@ -3016,6 +3016,8 @@ jumbo_split_static_library("ui") { ...@@ -3016,6 +3016,8 @@ jumbo_split_static_library("ui") {
"views/webauthn/transport_list_view.cc", "views/webauthn/transport_list_view.cc",
"views/webauthn/transport_list_view.h", "views/webauthn/transport_list_view.h",
"webauthn/authenticator_request_sheet_model.h", "webauthn/authenticator_request_sheet_model.h",
"webauthn/other_transports_menu_model.cc",
"webauthn/other_transports_menu_model.h",
"webauthn/sheet_models.cc", "webauthn/sheet_models.cc",
"webauthn/sheet_models.h", "webauthn/sheet_models.h",
"webauthn/transport_utils.cc", "webauthn/transport_utils.cc",
......
...@@ -59,6 +59,8 @@ class TestSheetModel : public AuthenticatorRequestSheetModel { ...@@ -59,6 +59,8 @@ class TestSheetModel : public AuthenticatorRequestSheetModel {
"Line Because Life Would Be Just Too Simple That Way"); "Line Because Life Would Be Just Too Simple That Way");
} }
ui::MenuModel* GetOtherTransportsMenuModel() override { return nullptr; }
void OnBack() override {} void OnBack() override {}
void OnAccept() override {} void OnAccept() override {}
void OnCancel() override {} void OnCancel() override {}
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h" #include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h"
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/views/border.h" #include "ui/views/border.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/window/dialog_client_view.h" #include "ui/views/window/dialog_client_view.h"
...@@ -77,6 +79,13 @@ gfx::Size AuthenticatorRequestDialogView::CalculatePreferredSize() const { ...@@ -77,6 +79,13 @@ gfx::Size AuthenticatorRequestDialogView::CalculatePreferredSize() const {
return gfx::Size(width, GetHeightForWidth(width)); return gfx::Size(width, GetHeightForWidth(width));
} }
views::View* AuthenticatorRequestDialogView::CreateExtraView() {
other_transports_button_ = views::MdTextButton::CreateSecondaryUiButton(
this, l10n_util::GetStringUTF16(IDS_WEBAUTHN_TRANSPORT_POPUP_LABEL));
ToggleOtherTransportsButtonVisibility();
return other_transports_button_;
}
bool AuthenticatorRequestDialogView::Accept() { bool AuthenticatorRequestDialogView::Accept() {
sheet()->model()->OnAccept(); sheet()->model()->OnAccept();
return false; return false;
...@@ -166,15 +175,36 @@ void AuthenticatorRequestDialogView::OnStepTransition() { ...@@ -166,15 +175,36 @@ void AuthenticatorRequestDialogView::OnStepTransition() {
} }
} }
void AuthenticatorRequestDialogView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
DCHECK_EQ(sender, other_transports_button_);
auto* other_transports_menu_model =
sheet_->model()->GetOtherTransportsMenuModel();
DCHECK(other_transports_menu_model);
DCHECK_GE(other_transports_menu_model->GetItemCount(), 1);
other_transports_menu_runner_ = std::make_unique<views::MenuRunner>(
other_transports_menu_model, views::MenuRunner::COMBOBOX);
gfx::Rect anchor_bounds = other_transports_button_->GetBoundsInScreen();
other_transports_menu_runner_->RunMenuAt(
other_transports_button_->GetWidget(), nullptr /* menu_button */,
anchor_bounds, views::MENU_ANCHOR_BUBBLE_BELOW, ui::MENU_SOURCE_MOUSE);
}
void AuthenticatorRequestDialogView::ReplaceCurrentSheetWith( void AuthenticatorRequestDialogView::ReplaceCurrentSheetWith(
std::unique_ptr<AuthenticatorRequestSheetView> new_sheet) { std::unique_ptr<AuthenticatorRequestSheetView> new_sheet) {
DCHECK(new_sheet); DCHECK(new_sheet);
other_transports_menu_runner_.reset();
delete sheet_; delete sheet_;
DCHECK(!has_children()); DCHECK(!has_children());
sheet_ = new_sheet.get(); sheet_ = new_sheet.get();
AddChildView(new_sheet.release()); AddChildView(new_sheet.release());
ToggleOtherTransportsButtonVisibility();
// The dialog button configuration is delegated to the |sheet_|, and the new // The dialog button configuration is delegated to the |sheet_|, and the new
// sheet likely wants to provide a new configuration. // sheet likely wants to provide a new configuration.
...@@ -214,3 +244,14 @@ void AuthenticatorRequestDialogView::ReplaceCurrentSheetWith( ...@@ -214,3 +244,14 @@ void AuthenticatorRequestDialogView::ReplaceCurrentSheetWith(
->delegate() ->delegate()
->GetWebContentsModalDialogHost()); ->GetWebContentsModalDialogHost());
} }
void AuthenticatorRequestDialogView::ToggleOtherTransportsButtonVisibility() {
// The button is not yet created when this is called for the first time.
if (!other_transports_button_)
return;
bool has_other_transports_menu =
sheet_->model()->GetOtherTransportsMenuModel() &&
sheet_->model()->GetOtherTransportsMenuModel()->GetItemCount();
other_transports_button_->SetVisible(has_other_transports_menu);
}
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/webauthn/authenticator_request_dialog_model.h" #include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/window/dialog_delegate.h" #include "ui/views/window/dialog_delegate.h"
namespace content { namespace content {
...@@ -32,7 +34,8 @@ class AuthenticatorRequestSheetView; ...@@ -32,7 +34,8 @@ class AuthenticatorRequestSheetView;
class AuthenticatorRequestDialogView class AuthenticatorRequestDialogView
: public views::DialogDelegateView, : public views::DialogDelegateView,
public AuthenticatorRequestDialogModel::Observer, public AuthenticatorRequestDialogModel::Observer,
public content::WebContentsObserver { public content::WebContentsObserver,
public views::ButtonListener {
public: public:
AuthenticatorRequestDialogView( AuthenticatorRequestDialogView(
content::WebContents* web_contents, content::WebContents* web_contents,
...@@ -47,6 +50,11 @@ class AuthenticatorRequestDialogView ...@@ -47,6 +50,11 @@ class AuthenticatorRequestDialogView
void ReplaceCurrentSheetWith( void ReplaceCurrentSheetWith(
std::unique_ptr<AuthenticatorRequestSheetView> new_sheet); std::unique_ptr<AuthenticatorRequestSheetView> new_sheet);
// Shows or hides the "Choose another option" button based on whether the
// current sheet model defines a model for the other transports popup menu,
// and whether it has at least one element.
void ToggleOtherTransportsButtonVisibility();
AuthenticatorRequestSheetView* sheet() const { AuthenticatorRequestSheetView* sheet() const {
DCHECK(sheet_); DCHECK(sheet_);
return sheet_; return sheet_;
...@@ -54,6 +62,7 @@ class AuthenticatorRequestDialogView ...@@ -54,6 +62,7 @@ class AuthenticatorRequestDialogView
// views::DialogDelegateView: // views::DialogDelegateView:
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
views::View* CreateExtraView() override;
bool Accept() override; bool Accept() override;
bool Cancel() override; bool Cancel() override;
bool Close() override; bool Close() override;
...@@ -70,11 +79,17 @@ class AuthenticatorRequestDialogView ...@@ -70,11 +79,17 @@ class AuthenticatorRequestDialogView
void OnModelDestroyed() override; void OnModelDestroyed() override;
void OnStepTransition() override; void OnStepTransition() override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
private: private:
friend class test::AuthenticatorRequestDialogViewTestApi; friend class test::AuthenticatorRequestDialogViewTestApi;
std::unique_ptr<AuthenticatorRequestDialogModel> model_; std::unique_ptr<AuthenticatorRequestDialogModel> model_;
AuthenticatorRequestSheetView* sheet_ = nullptr; AuthenticatorRequestSheetView* sheet_ = nullptr;
views::Button* other_transports_button_ = nullptr;
std::unique_ptr<views::MenuRunner> other_transports_menu_runner_;
DISALLOW_COPY_AND_ASSIGN(AuthenticatorRequestDialogView); DISALLOW_COPY_AND_ASSIGN(AuthenticatorRequestDialogView);
}; };
......
...@@ -41,8 +41,8 @@ std::unique_ptr<HoverButton> CreateTransportListItemView( ...@@ -41,8 +41,8 @@ std::unique_ptr<HoverButton> CreateTransportListItemView(
transport_image->SetImage(gfx::CreateVectorIcon( transport_image->SetImage(gfx::CreateVectorIcon(
GetTransportVectorIcon(transport), kTransportIconSize, icon_color)); GetTransportVectorIcon(transport), kTransportIconSize, icon_color));
const base::string16 transport_name = const base::string16 transport_name = GetTransportHumanReadableName(
GetTransportHumanReadableName(transport); transport, TransportSelectionContext::kTransportSelectionSheet);
auto chevron_image = std::make_unique<views::ImageView>(); auto chevron_image = std::make_unique<views::ImageView>();
chevron_image->SetImage( chevron_image->SetImage(
......
...@@ -22,21 +22,18 @@ class AuthenticatorDialogTest : public DialogBrowserTest { ...@@ -22,21 +22,18 @@ class AuthenticatorDialogTest : public DialogBrowserTest {
::device::FidoRequestHandlerBase::TransportAvailabilityInfo ::device::FidoRequestHandlerBase::TransportAvailabilityInfo
transport_availability; transport_availability;
transport_availability.rp_id = "example.com"; transport_availability.rp_id = "example.com";
transport_availability.available_transports = {
AuthenticatorTransport::kBluetoothLowEnergy,
AuthenticatorTransport::kUsbHumanInterfaceDevice,
AuthenticatorTransport::kNearFieldCommunication,
AuthenticatorTransport::kInternal,
AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy};
model->StartFlow(std::move(transport_availability), base::nullopt); model->StartFlow(std::move(transport_availability), base::nullopt);
// The dialog should immediately close as soon as it is displayed. // The dialog should immediately close as soon as it is displayed.
if (name == "completed") { if (name == "completed") {
model->SetCurrentStep(AuthenticatorRequestDialogModel::Step::kCompleted); model->SetCurrentStep(AuthenticatorRequestDialogModel::Step::kCompleted);
} else if (name == "transports") { } else if (name == "transports") {
TransportListModel* transports = model->transport_list_model();
transports->AppendTransport(AuthenticatorTransport::kBluetoothLowEnergy);
transports->AppendTransport(
AuthenticatorTransport::kUsbHumanInterfaceDevice);
transports->AppendTransport(
AuthenticatorTransport::kNearFieldCommunication);
transports->AppendTransport(AuthenticatorTransport::kInternal);
transports->AppendTransport(
AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy);
model->SetCurrentStep( model->SetCurrentStep(
AuthenticatorRequestDialogModel::Step::kTransportSelection); AuthenticatorRequestDialogModel::Step::kTransportSelection);
} else if (name == "activate_usb") { } else if (name == "activate_usb") {
......
...@@ -13,6 +13,10 @@ namespace gfx { ...@@ -13,6 +13,10 @@ namespace gfx {
class ImageSkia; class ImageSkia;
} }
namespace ui {
class MenuModel;
}
// The basic interface of models backing a given UI sheet shown in the WebAuthn // The basic interface of models backing a given UI sheet shown in the WebAuthn
// request dialog; where each sheet, in turn, corresponds to one of `steps` // request dialog; where each sheet, in turn, corresponds to one of `steps`
// defined by AuthenticatorRequestDialogModel. // defined by AuthenticatorRequestDialogModel.
...@@ -50,6 +54,8 @@ class AuthenticatorRequestSheetModel { ...@@ -50,6 +54,8 @@ class AuthenticatorRequestSheetModel {
virtual base::string16 GetStepTitle() const = 0; virtual base::string16 GetStepTitle() const = 0;
virtual base::string16 GetStepDescription() const = 0; virtual base::string16 GetStepDescription() const = 0;
virtual ui::MenuModel* GetOtherTransportsMenuModel() = 0;
virtual void OnBack() = 0; virtual void OnBack() = 0;
virtual void OnAccept() = 0; virtual void OnAccept() = 0;
virtual void OnCancel() = 0; virtual void OnCancel() = 0;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webauthn/other_transports_menu_model.h"
#include "base/numerics/safe_conversions.h"
#include "chrome/browser/ui/webauthn/transport_utils.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/paint_vector_icon.h"
namespace {
gfx::ImageSkia GetTransportIcon(AuthenticatorTransport transport) {
constexpr int kTransportIconSize = 24;
return gfx::CreateVectorIcon(GetTransportVectorIcon(transport),
kTransportIconSize, gfx::kGoogleGrey700);
}
} // namespace
OtherTransportsMenuModel::OtherTransportsMenuModel(
AuthenticatorRequestDialogModel* dialog_model,
AuthenticatorTransport current_transport)
: ui::SimpleMenuModel(this), dialog_model_(dialog_model) {
DCHECK(dialog_model);
dialog_model_->AddObserver(this);
if (current_transport == AuthenticatorTransport::kBluetoothLowEnergy)
AppendItemForAnotherBluetoothKey();
PopulateWithTransportsExceptFor(current_transport);
}
OtherTransportsMenuModel::~OtherTransportsMenuModel() {
if (dialog_model_) {
dialog_model_->RemoveObserver(this);
dialog_model_ = nullptr;
}
}
void OtherTransportsMenuModel::PopulateWithTransportsExceptFor(
AuthenticatorTransport current_transport) {
for (const auto transport :
dialog_model_->transport_availability()->available_transports) {
if (transport == current_transport)
continue;
auto name = GetTransportHumanReadableName(
transport, TransportSelectionContext::kOtherTransportsMenu);
AddItemWithIcon(base::strict_cast<int>(transport), std::move(name),
GetTransportIcon(transport));
}
}
void OtherTransportsMenuModel::AppendItemForAnotherBluetoothKey() {
AddItemWithIcon(
base::strict_cast<int>(AuthenticatorTransport::kBluetoothLowEnergy),
l10n_util::GetStringUTF16(IDS_WEBAUTHN_TRANSPORT_POPUP_ANOTHER_BLE),
GetTransportIcon(AuthenticatorTransport::kBluetoothLowEnergy));
}
bool OtherTransportsMenuModel::IsCommandIdChecked(int command_id) const {
return false;
}
bool OtherTransportsMenuModel::IsCommandIdEnabled(int command_id) const {
return true;
}
void OtherTransportsMenuModel::ExecuteCommand(int command_id, int event_flags) {
AuthenticatorTransport selected_transport =
static_cast<AuthenticatorTransport>(command_id);
DCHECK(dialog_model_);
dialog_model_->StartGuidedFlowForTransport(selected_transport);
}
void OtherTransportsMenuModel::OnModelDestroyed() {
dialog_model_ = nullptr;
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBAUTHN_OTHER_TRANSPORTS_MENU_MODEL_H_
#define CHROME_BROWSER_UI_WEBAUTHN_OTHER_TRANSPORTS_MENU_MODEL_H_
#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
#include "ui/base/models/simple_menu_model.h"
// The model of the pop-up menu shown when `Choose another option` is clicked.
//
// This pop-up menu is available on several sheets instructing the user to
// activate their security key over a given transport, and allows the user to
// instead use a different transport protocol.
class OtherTransportsMenuModel
: public ui::SimpleMenuModel,
public ui::SimpleMenuModel::Delegate,
public AuthenticatorRequestDialogModel::Observer {
public:
OtherTransportsMenuModel(AuthenticatorRequestDialogModel* dialog_model,
AuthenticatorTransport current_transport);
~OtherTransportsMenuModel() override;
protected:
// ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
void ExecuteCommand(int command_id, int event_flags) override;
// AuthenticatorRequestDialogModel::Observer:
void OnModelDestroyed() override;
private:
// Appends all available transports except the |current_transport|
void PopulateWithTransportsExceptFor(
AuthenticatorTransport current_transport);
// Appends the item representing using BLE with a not-yet-paired security key.
void AppendItemForAnotherBluetoothKey();
AuthenticatorRequestDialogModel* dialog_model_;
DISALLOW_COPY_AND_ASSIGN(OtherTransportsMenuModel);
};
#endif // CHROME_BROWSER_UI_WEBAUTHN_OTHER_TRANSPORTS_MENU_MODEL_H_
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/ui/webauthn/other_transports_menu_model.h"
#include "chrome/grit/browser_resources.h" #include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
...@@ -66,6 +67,10 @@ base::string16 AuthenticatorSheetModelBase::GetAcceptButtonLabel() const { ...@@ -66,6 +67,10 @@ base::string16 AuthenticatorSheetModelBase::GetAcceptButtonLabel() const {
return base::string16(); return base::string16();
} }
ui::MenuModel* AuthenticatorSheetModelBase::GetOtherTransportsMenuModel() {
return nullptr;
}
void AuthenticatorSheetModelBase::OnBack() { void AuthenticatorSheetModelBase::OnBack() {
if (dialog_model()) if (dialog_model())
dialog_model()->Back(); dialog_model()->Back();
...@@ -146,6 +151,17 @@ void AuthenticatorTransportSelectorSheetModel::OnTransportSelected( ...@@ -146,6 +151,17 @@ void AuthenticatorTransportSelectorSheetModel::OnTransportSelected(
// AuthenticatorInsertAndActivateUsbSheetModel ---------------------- // AuthenticatorInsertAndActivateUsbSheetModel ----------------------
AuthenticatorInsertAndActivateUsbSheetModel::
AuthenticatorInsertAndActivateUsbSheetModel(
AuthenticatorRequestDialogModel* dialog_model)
: AuthenticatorSheetModelBase(dialog_model) {
other_transports_menu_model_ = std::make_unique<OtherTransportsMenuModel>(
dialog_model, AuthenticatorTransport::kUsbHumanInterfaceDevice);
}
AuthenticatorInsertAndActivateUsbSheetModel::
~AuthenticatorInsertAndActivateUsbSheetModel() = default;
bool AuthenticatorInsertAndActivateUsbSheetModel::IsActivityIndicatorVisible() bool AuthenticatorInsertAndActivateUsbSheetModel::IsActivityIndicatorVisible()
const { const {
return true; return true;
...@@ -167,6 +183,11 @@ base::string16 AuthenticatorInsertAndActivateUsbSheetModel::GetStepDescription() ...@@ -167,6 +183,11 @@ base::string16 AuthenticatorInsertAndActivateUsbSheetModel::GetStepDescription()
return l10n_util::GetStringUTF16(IDS_WEBAUTHN_USB_ACTIVATE_DESCRIPTION); return l10n_util::GetStringUTF16(IDS_WEBAUTHN_USB_ACTIVATE_DESCRIPTION);
} }
ui::MenuModel*
AuthenticatorInsertAndActivateUsbSheetModel::GetOtherTransportsMenuModel() {
return other_transports_menu_model_.get();
}
// AuthenticatorTimeoutErrorModel --------------------------------------------- // AuthenticatorTimeoutErrorModel ---------------------------------------------
gfx::ImageSkia* AuthenticatorTimeoutErrorModel::GetStepIllustration() const { gfx::ImageSkia* AuthenticatorTimeoutErrorModel::GetStepIllustration() const {
...@@ -424,6 +445,16 @@ base::string16 AuthenticatorBleVerifyingSheetModel::GetStepDescription() const { ...@@ -424,6 +445,16 @@ base::string16 AuthenticatorBleVerifyingSheetModel::GetStepDescription() const {
// AuthenticatorBleActivateSheetModel ----------------------------------------- // AuthenticatorBleActivateSheetModel -----------------------------------------
AuthenticatorBleActivateSheetModel::AuthenticatorBleActivateSheetModel(
AuthenticatorRequestDialogModel* dialog_model)
: AuthenticatorSheetModelBase(dialog_model) {
other_transports_menu_model_ = std::make_unique<OtherTransportsMenuModel>(
dialog_model, AuthenticatorTransport::kBluetoothLowEnergy);
}
AuthenticatorBleActivateSheetModel::~AuthenticatorBleActivateSheetModel() =
default;
bool AuthenticatorBleActivateSheetModel::IsActivityIndicatorVisible() const { bool AuthenticatorBleActivateSheetModel::IsActivityIndicatorVisible() const {
return true; return true;
} }
...@@ -442,8 +473,22 @@ base::string16 AuthenticatorBleActivateSheetModel::GetStepDescription() const { ...@@ -442,8 +473,22 @@ base::string16 AuthenticatorBleActivateSheetModel::GetStepDescription() const {
return l10n_util::GetStringUTF16(IDS_WEBAUTHN_BLE_ACTIVATE_DESCRIPTION); return l10n_util::GetStringUTF16(IDS_WEBAUTHN_BLE_ACTIVATE_DESCRIPTION);
} }
ui::MenuModel*
AuthenticatorBleActivateSheetModel::GetOtherTransportsMenuModel() {
return other_transports_menu_model_.get();
}
// AuthenticatorTouchIdSheetModel ----------------------------------------- // AuthenticatorTouchIdSheetModel -----------------------------------------
AuthenticatorTouchIdSheetModel::AuthenticatorTouchIdSheetModel(
AuthenticatorRequestDialogModel* dialog_model)
: AuthenticatorSheetModelBase(dialog_model) {
other_transports_menu_model_ = std::make_unique<OtherTransportsMenuModel>(
dialog_model, AuthenticatorTransport::kInternal);
}
AuthenticatorTouchIdSheetModel::~AuthenticatorTouchIdSheetModel() = default;
bool AuthenticatorTouchIdSheetModel::IsActivityIndicatorVisible() const { bool AuthenticatorTouchIdSheetModel::IsActivityIndicatorVisible() const {
return true; return true;
} }
...@@ -476,8 +521,25 @@ base::string16 AuthenticatorTouchIdSheetModel::GetStepDescription() const { ...@@ -476,8 +521,25 @@ base::string16 AuthenticatorTouchIdSheetModel::GetStepDescription() const {
return base::string16(); return base::string16();
} }
ui::MenuModel* AuthenticatorTouchIdSheetModel::GetOtherTransportsMenuModel() {
if (!other_transports_menu_model_) {
other_transports_menu_model_ = std::make_unique<OtherTransportsMenuModel>(
dialog_model(), AuthenticatorTransport::kInternal);
}
return other_transports_menu_model_.get();
}
// AuthenticatorPaaskSheetModel ----------------------------------------- // AuthenticatorPaaskSheetModel -----------------------------------------
AuthenticatorPaaskSheetModel::AuthenticatorPaaskSheetModel(
AuthenticatorRequestDialogModel* dialog_model)
: AuthenticatorSheetModelBase(dialog_model) {
other_transports_menu_model_ = std::make_unique<OtherTransportsMenuModel>(
dialog_model, AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy);
}
AuthenticatorPaaskSheetModel::~AuthenticatorPaaskSheetModel() = default;
bool AuthenticatorPaaskSheetModel::IsActivityIndicatorVisible() const { bool AuthenticatorPaaskSheetModel::IsActivityIndicatorVisible() const {
return true; return true;
} }
...@@ -493,3 +555,7 @@ base::string16 AuthenticatorPaaskSheetModel::GetStepTitle() const { ...@@ -493,3 +555,7 @@ base::string16 AuthenticatorPaaskSheetModel::GetStepTitle() const {
base::string16 AuthenticatorPaaskSheetModel::GetStepDescription() const { base::string16 AuthenticatorPaaskSheetModel::GetStepDescription() const {
return l10n_util::GetStringUTF16(IDS_WEBAUTHN_CABLE_ACTIVATE_DESCRIPTION); return l10n_util::GetStringUTF16(IDS_WEBAUTHN_CABLE_ACTIVATE_DESCRIPTION);
} }
ui::MenuModel* AuthenticatorPaaskSheetModel::GetOtherTransportsMenuModel() {
return other_transports_menu_model_.get();
}
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
#include "chrome/browser/webauthn/authenticator_request_dialog_model.h" #include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
#include "chrome/browser/webauthn/transport_list_model.h" #include "chrome/browser/webauthn/transport_list_model.h"
namespace ui {
class MenuModel;
}
class OtherTransportsMenuModel;
// Base class for sheets, implementing the shared behavior used on most sheets, // Base class for sheets, implementing the shared behavior used on most sheets,
// as well as maintaining a weak pointer to the dialog model. // as well as maintaining a weak pointer to the dialog model.
class AuthenticatorSheetModelBase class AuthenticatorSheetModelBase
...@@ -40,6 +46,7 @@ class AuthenticatorSheetModelBase ...@@ -40,6 +46,7 @@ class AuthenticatorSheetModelBase
bool IsAcceptButtonVisible() const override; bool IsAcceptButtonVisible() const override;
bool IsAcceptButtonEnabled() const override; bool IsAcceptButtonEnabled() const override;
base::string16 GetAcceptButtonLabel() const override; base::string16 GetAcceptButtonLabel() const override;
ui::MenuModel* GetOtherTransportsMenuModel() override;
void OnBack() override; void OnBack() override;
void OnAccept() override; void OnAccept() override;
void OnCancel() override; void OnCancel() override;
...@@ -90,7 +97,9 @@ class AuthenticatorTransportSelectorSheetModel ...@@ -90,7 +97,9 @@ class AuthenticatorTransportSelectorSheetModel
class AuthenticatorInsertAndActivateUsbSheetModel class AuthenticatorInsertAndActivateUsbSheetModel
: public AuthenticatorSheetModelBase { : public AuthenticatorSheetModelBase {
public: public:
using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase; explicit AuthenticatorInsertAndActivateUsbSheetModel(
AuthenticatorRequestDialogModel* dialog_model);
~AuthenticatorInsertAndActivateUsbSheetModel() override;
private: private:
// AuthenticatorSheetModelBase: // AuthenticatorSheetModelBase:
...@@ -98,6 +107,9 @@ class AuthenticatorInsertAndActivateUsbSheetModel ...@@ -98,6 +107,9 @@ class AuthenticatorInsertAndActivateUsbSheetModel
gfx::ImageSkia* GetStepIllustration() const override; gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override; base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override; base::string16 GetStepDescription() const override;
ui::MenuModel* GetOtherTransportsMenuModel() override;
std::unique_ptr<OtherTransportsMenuModel> other_transports_menu_model_;
}; };
class AuthenticatorTimeoutErrorModel : public AuthenticatorSheetModelBase { class AuthenticatorTimeoutErrorModel : public AuthenticatorSheetModelBase {
...@@ -240,7 +252,9 @@ class AuthenticatorBleVerifyingSheetModel : public AuthenticatorSheetModelBase { ...@@ -240,7 +252,9 @@ class AuthenticatorBleVerifyingSheetModel : public AuthenticatorSheetModelBase {
class AuthenticatorBleActivateSheetModel : public AuthenticatorSheetModelBase { class AuthenticatorBleActivateSheetModel : public AuthenticatorSheetModelBase {
public: public:
using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase; explicit AuthenticatorBleActivateSheetModel(
AuthenticatorRequestDialogModel* dialog_model);
~AuthenticatorBleActivateSheetModel() override;
private: private:
// AuthenticatorSheetModelBase: // AuthenticatorSheetModelBase:
...@@ -248,11 +262,16 @@ class AuthenticatorBleActivateSheetModel : public AuthenticatorSheetModelBase { ...@@ -248,11 +262,16 @@ class AuthenticatorBleActivateSheetModel : public AuthenticatorSheetModelBase {
gfx::ImageSkia* GetStepIllustration() const override; gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override; base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override; base::string16 GetStepDescription() const override;
ui::MenuModel* GetOtherTransportsMenuModel() override;
std::unique_ptr<OtherTransportsMenuModel> other_transports_menu_model_;
}; };
class AuthenticatorTouchIdSheetModel : public AuthenticatorSheetModelBase { class AuthenticatorTouchIdSheetModel : public AuthenticatorSheetModelBase {
public: public:
using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase; explicit AuthenticatorTouchIdSheetModel(
AuthenticatorRequestDialogModel* dialog_model);
~AuthenticatorTouchIdSheetModel() override;
private: private:
// AuthenticatorSheetModelBase: // AuthenticatorSheetModelBase:
...@@ -261,11 +280,16 @@ class AuthenticatorTouchIdSheetModel : public AuthenticatorSheetModelBase { ...@@ -261,11 +280,16 @@ class AuthenticatorTouchIdSheetModel : public AuthenticatorSheetModelBase {
gfx::ImageSkia* GetStepIllustration() const override; gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override; base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override; base::string16 GetStepDescription() const override;
ui::MenuModel* GetOtherTransportsMenuModel() override;
std::unique_ptr<OtherTransportsMenuModel> other_transports_menu_model_;
}; };
class AuthenticatorPaaskSheetModel : public AuthenticatorSheetModelBase { class AuthenticatorPaaskSheetModel : public AuthenticatorSheetModelBase {
public: public:
using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase; explicit AuthenticatorPaaskSheetModel(
AuthenticatorRequestDialogModel* dialog_model);
~AuthenticatorPaaskSheetModel() override;
private: private:
// AuthenticatorSheetModelBase: // AuthenticatorSheetModelBase:
...@@ -273,6 +297,9 @@ class AuthenticatorPaaskSheetModel : public AuthenticatorSheetModelBase { ...@@ -273,6 +297,9 @@ class AuthenticatorPaaskSheetModel : public AuthenticatorSheetModelBase {
gfx::ImageSkia* GetStepIllustration() const override; gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override; base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override; base::string16 GetStepDescription() const override;
ui::MenuModel* GetOtherTransportsMenuModel() override;
std::unique_ptr<OtherTransportsMenuModel> other_transports_menu_model_;
}; };
#endif // CHROME_BROWSER_UI_WEBAUTHN_SHEET_MODELS_H_ #endif // CHROME_BROWSER_UI_WEBAUTHN_SHEET_MODELS_H_
...@@ -10,25 +10,53 @@ ...@@ -10,25 +10,53 @@
#include "components/vector_icons/vector_icons.h" #include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
base::string16 GetTransportHumanReadableName(AuthenticatorTransport transport) { namespace {
int message_id = 0;
int GetMessageIdForTransportOnTransportSelectionSheet(
AuthenticatorTransport transport) {
switch (transport) { switch (transport) {
case AuthenticatorTransport::kBluetoothLowEnergy: case AuthenticatorTransport::kBluetoothLowEnergy:
message_id = IDS_WEBAUTHN_TRANSPORT_BLE; return IDS_WEBAUTHN_TRANSPORT_BLE;
break;
case AuthenticatorTransport::kNearFieldCommunication: case AuthenticatorTransport::kNearFieldCommunication:
message_id = IDS_WEBAUTHN_TRANSPORT_NFC; return IDS_WEBAUTHN_TRANSPORT_NFC;
break;
case AuthenticatorTransport::kUsbHumanInterfaceDevice: case AuthenticatorTransport::kUsbHumanInterfaceDevice:
message_id = IDS_WEBAUTHN_TRANSPORT_USB; return IDS_WEBAUTHN_TRANSPORT_USB;
break;
case AuthenticatorTransport::kInternal: case AuthenticatorTransport::kInternal:
message_id = IDS_WEBAUTHN_TRANSPORT_INTERNAL; return IDS_WEBAUTHN_TRANSPORT_INTERNAL;
break;
case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy: case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
message_id = IDS_WEBAUTHN_TRANSPORT_CABLE; return IDS_WEBAUTHN_TRANSPORT_CABLE;
break;
} }
NOTREACHED();
return 0;
}
int GetMessageIdForTransportOnOtherTransportsPopup(
AuthenticatorTransport transport) {
switch (transport) {
case AuthenticatorTransport::kBluetoothLowEnergy:
return IDS_WEBAUTHN_TRANSPORT_POPUP_BLE;
case AuthenticatorTransport::kNearFieldCommunication:
return IDS_WEBAUTHN_TRANSPORT_POPUP_NFC;
case AuthenticatorTransport::kUsbHumanInterfaceDevice:
return IDS_WEBAUTHN_TRANSPORT_POPUP_USB;
case AuthenticatorTransport::kInternal:
return IDS_WEBAUTHN_TRANSPORT_POPUP_INTERNAL;
case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
return IDS_WEBAUTHN_TRANSPORT_POPUP_CABLE;
}
NOTREACHED();
return 0;
}
} // namespace
base::string16 GetTransportHumanReadableName(
AuthenticatorTransport transport,
TransportSelectionContext context) {
int message_id =
context == TransportSelectionContext::kTransportSelectionSheet
? GetMessageIdForTransportOnTransportSelectionSheet(transport)
: GetMessageIdForTransportOnOtherTransportsPopup(transport);
DCHECK_NE(message_id, 0); DCHECK_NE(message_id, 0);
return l10n_util::GetStringUTF16(message_id); return l10n_util::GetStringUTF16(message_id);
} }
......
...@@ -12,9 +12,14 @@ namespace gfx { ...@@ -12,9 +12,14 @@ namespace gfx {
struct VectorIcon; struct VectorIcon;
} }
// Returns the human readable name of |transport| to show in the manual enum class TransportSelectionContext {
// transport selection list. kTransportSelectionSheet,
base::string16 GetTransportHumanReadableName(AuthenticatorTransport transport); kOtherTransportsMenu,
};
// Returns the human readable name shown for |transport| in the given |context|.
base::string16 GetTransportHumanReadableName(AuthenticatorTransport transport,
TransportSelectionContext context);
// Returns the vector icon to show next to the |transport| in the manual // Returns the vector icon to show next to the |transport| in the manual
// transport selection list. // transport selection list.
......
...@@ -113,6 +113,10 @@ void AuthenticatorRequestDialogModel::StartGuidedFlowForTransport( ...@@ -113,6 +113,10 @@ void AuthenticatorRequestDialogModel::StartGuidedFlowForTransport(
AuthenticatorTransport transport) { AuthenticatorTransport transport) {
DCHECK(current_step() == Step::kTransportSelection || DCHECK(current_step() == Step::kTransportSelection ||
current_step() == Step::kWelcomeScreen || current_step() == Step::kWelcomeScreen ||
current_step() == Step::kUsbInsertAndActivate ||
current_step() == Step::kTouchId ||
current_step() == Step::kBleActivate ||
current_step() == Step::kCableActivate ||
current_step() == Step::kNotStarted); current_step() == Step::kNotStarted);
switch (transport) { switch (transport) {
case AuthenticatorTransport::kUsbHumanInterfaceDevice: case AuthenticatorTransport::kUsbHumanInterfaceDevice:
......
...@@ -124,7 +124,8 @@ class AuthenticatorRequestDialogModel { ...@@ -124,7 +124,8 @@ class AuthenticatorRequestDialogModel {
// through using the Secutity Key with the given |transport|. // through using the Secutity Key with the given |transport|.
// //
// Valid action when at step: kNotStarted, kWelcomeScreen, // Valid action when at step: kNotStarted, kWelcomeScreen,
// kTransportSelection. // kTransportSelection, and steps where the other transports menu is shown,
// namely, kUsbInsertAndActivate, kTouchId, kBleActivate, kCableActivate.
void StartGuidedFlowForTransport(AuthenticatorTransport transport); void StartGuidedFlowForTransport(AuthenticatorTransport transport);
// Tries if the BLE adapter is now powered -- the user claims they turned it // Tries if the BLE adapter is now powered -- the user claims they turned it
......
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