1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/auth_panel/impl/auth_panel.h"
#include <memory>
#include <vector>
#include "ash/auth/views/auth_textfield.h"
#include "ash/login/ui/arrow_button_view.h"
#include "ash/login/ui/non_accessible_view.h"
#include "ash/public/cpp/ime_controller.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "chromeos/ash/components/auth_panel/impl/auth_factor_store.h"
#include "chromeos/ash/components/auth_panel/impl/auth_panel_event_dispatcher.h"
#include "chromeos/ash/components/auth_panel/impl/factor_auth_view.h"
#include "chromeos/ash/components/auth_panel/impl/factor_auth_view_factory.h"
#include "chromeos/ash/components/auth_panel/impl/views/password_auth_view.h"
#include "chromeos/ash/components/osauth/public/auth_factor_status_consumer.h"
#include "chromeos/ash/components/osauth/public/common_types.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/toggle_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/layout_types.h"
namespace ash {
namespace {
std::optional<AshAuthFactor> GetPasswordFactorType(AuthFactorsSet factors) {
bool has_local_password = factors.Has(AshAuthFactor::kLocalPassword);
bool has_gaia_password = factors.Has(AshAuthFactor::kGaiaPassword);
// We currently only support having either local passwords or gaia passwords,
// but not both.
CHECK(!has_local_password || !has_gaia_password);
if (has_local_password) {
return AshAuthFactor::kLocalPassword;
} else if (has_gaia_password) {
return AshAuthFactor::kGaiaPassword;
} else {
return std::nullopt;
}
}
} // namespace
AuthPanel::TestApi::TestApi(AuthPanel* auth_panel) : auth_panel_(auth_panel) {}
AuthPanel::TestApi::~TestApi() = default;
PasswordAuthView* AuthPanel::TestApi::GetPasswordAuthView() {
auto password_view_wrapper =
auth_panel_->views_[AshAuthFactor::kLocalPassword]
? auth_panel_->views_[AshAuthFactor::kLocalPassword]
: auth_panel_->views_[AshAuthFactor::kGaiaPassword];
auto children = password_view_wrapper->GetChildrenInZOrder();
// Each wrapper should only contain a single FactorAuthView.
// Verify this invariant here.
CHECK(children.size() == 1);
return static_cast<PasswordAuthView*>(children.front());
}
void AuthPanel::TestApi::SetSubmitPasswordCallback(
auth_panel::SubmitPasswordCallback callback) {
auth_panel_->store_->submit_password_callback_ = std::move(callback);
}
AuthPanel::AuthPanel(
std::unique_ptr<FactorAuthViewFactory> view_factory,
std::unique_ptr<AuthFactorStoreFactory> store_factory,
std::unique_ptr<AuthPanelEventDispatcherFactory> event_dispatcher_factory,
base::OnceClosure on_end_authentication,
base::RepeatingClosure on_prefered_size_changed,
AuthHubConnector* connector)
: event_dispatcher_factory_(std::move(event_dispatcher_factory)),
view_factory_(std::move(view_factory)),
store_factory_(std::move(store_factory)),
on_end_authentication_(std::move(on_end_authentication)),
on_ui_changed_(std::move(on_prefered_size_changed)),
auth_hub_connector_(connector) {
SetLayoutManager(std::make_unique<views::FlexLayout>())
->SetOrientation(views::LayoutOrientation::kVertical)
.SetMainAxisAlignment(views::LayoutAlignment::kCenter)
.SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
.SetCollapseMargins(false);
InitializeViewPlaceholders();
}
AuthPanel::~AuthPanel() = default;
void AuthPanel::InitializeViewPlaceholders() {
// The order in which the views will be laid out in AuthPanel. We create
// placeholder spots for them in the UI beforehand, and fill them out later
// depending on the presence of factors.
std::vector<AshAuthFactor> view_order{
AshAuthFactor::kGaiaPassword,
};
for (AshAuthFactor factor : view_order) {
views_[factor] = AddChildView(std::make_unique<NonAccessibleView>());
views_[factor]->SetLayoutManager(std::make_unique<views::FlexLayout>());
}
}
void AuthPanel::InitializeUi(AuthFactorsSet factors,
AuthHubConnector* connector) {
std::optional<AshAuthFactor> password_type = GetPasswordFactorType(factors);
store_ =
store_factory_->CreateAuthFactorStore(ImeController::Get(), connector,
/*password_type=*/password_type);
event_dispatcher_ =
event_dispatcher_factory_->CreateAuthPanelEventDispatcher(store_.get());
for (auto&& factor : factors) {
auto factor_auth_view = view_factory_->CreateFactorAuthView(
factor, store_.get(), event_dispatcher_.get());
if (factor_auth_view != nullptr) {
// We ignore views that the factory doesn't know how to construct.
views_[factor]->AddChildView(std::move(factor_auth_view));
}
event_dispatcher_->DispatchEvent(factor,
AuthFactorState::kCheckingForPresence);
}
on_ui_changed_.Run();
}
void AuthPanel::OnFactorListChanged(FactorsStatusMap factors_with_status) {
// Here, the list of auth factors can potentially change. Previously
// available auth factors (at the time of `AuthPanel::InitializeUI`) can now
// be unavailable. The converse is also true.
// Existing auth factors can have their status changed.
// To that end, we destroy the UI and recreate it, to ensure consistency.
// It is also assumed that the password type will not change from
// `kGaiaPassword` to `kLocalPassword` or vice-versa. Therefore we don't have
// to inform `store_` of a new password type.
// Order of operations is important, removing child views before clearing
// our non-owning references will cause them to dangle.
views_.clear();
RemoveAllChildViews();
InitializeViewPlaceholders();
for (const auto& [factor, status] : factors_with_status) {
auto factor_auth_view = view_factory_->CreateFactorAuthView(
factor, store_.get(), event_dispatcher_.get());
if (factor_auth_view != nullptr) {
// We ignore views that the factory doesn't know how to construct.
views_[factor]->AddChildView(std::move(factor_auth_view));
}
event_dispatcher_->DispatchEvent(factor, status);
}
on_ui_changed_.Run();
}
void AuthPanel::OnFactorStatusesChanged(FactorsStatusMap incremental_update) {
for (const auto& [factor, status] : incremental_update) {
event_dispatcher_->DispatchEvent(factor, status);
}
}
void AuthPanel::OnFactorCustomSignal(AshAuthFactor factor) {
NOTIMPLEMENTED();
}
void AuthPanel::OnFactorAuthFailure(AshAuthFactor factor) {
event_dispatcher_->DispatchEvent(
factor, AuthPanelEventDispatcher::AuthVerdict::kFailure);
}
void AuthPanel::OnFactorAuthSuccess(AshAuthFactor factor) {
event_dispatcher_->DispatchEvent(
factor, AuthPanelEventDispatcher::AuthVerdict::kSuccess);
}
void AuthPanel::OnEndAuthentication() {
auth_hub_connector_ = nullptr;
std::move(on_end_authentication_).Run();
}
BEGIN_METADATA(AuthPanel)
END_METADATA
} // namespace ash
|