1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/login/security_token_request_controller.h"
6 
7 #include <utility>
8 
9 #include "ash/login/ui/pin_request_widget.h"
10 #include "ash/public/cpp/login_types.h"
11 #include "ash/strings/grit/ash_strings.h"
12 #include "base/bind.h"
13 #include "base/i18n/number_formatting.h"
14 #include "base/strings/string16.h"
15 #include "chromeos/components/security_token_pin/error_generator.h"
16 #include "ui/base/l10n/l10n_util.h"
17 
18 namespace ash {
19 
20 namespace {
21 
GetTitle()22 base::string16 GetTitle() {
23   return l10n_util::GetStringUTF16(
24       IDS_ASH_LOGIN_SECURITY_TOKEN_REQUEST_DIALOG_TITLE);
25 }
26 
GetDescription()27 base::string16 GetDescription() {
28   return l10n_util::GetStringUTF16(
29       IDS_ASH_LOGIN_SECURITY_TOKEN_REQUEST_DIALOG_DESCRIPTION);
30 }
31 
GetAccessibleTitle()32 base::string16 GetAccessibleTitle() {
33   return l10n_util::GetStringUTF16(
34       IDS_ASH_LOGIN_SECURITY_TOKEN_REQUEST_DIALOG_TITLE);
35 }
36 
37 }  // namespace
38 
39 SecurityTokenRequestController::SecurityTokenRequestController() = default;
40 
~SecurityTokenRequestController()41 SecurityTokenRequestController::~SecurityTokenRequestController() {
42   ClosePinUi();
43 }
44 
ResetRequestCanceled()45 void SecurityTokenRequestController::ResetRequestCanceled() {
46   request_canceled_ = false;
47 }
48 
OnPinSubmitted(const std::string & code)49 PinRequestView::SubmissionResult SecurityTokenRequestController::OnPinSubmitted(
50     const std::string& code) {
51   if (!on_pin_submitted_.is_null()) {
52     std::move(on_pin_submitted_).Run(code);
53   }
54   return PinRequestView::SubmissionResult::kSubmitPending;
55 }
56 
OnBack()57 void SecurityTokenRequestController::OnBack() {
58   request_canceled_ = true;
59   if (!on_canceled_by_user_.is_null()) {
60     std::move(on_canceled_by_user_).Run();
61   }
62   ClosePinUi();
63 }
64 
OnHelp(gfx::NativeWindow parent_window)65 void SecurityTokenRequestController::OnHelp(gfx::NativeWindow parent_window) {
66   NOTREACHED();
67 }
68 
SetPinUiState(SecurityTokenPinRequest request)69 bool SecurityTokenRequestController::SetPinUiState(
70     SecurityTokenPinRequest request) {
71   // Unable to request a PIN while the PinRequestWidget is already used for
72   // something that is not a SecurityTokenPinRequest.
73   // Also deny the request when the user has just canceled another request: For
74   // example, logging in with smart cards usually requires two requests for the
75   // same PIN. When the user has canceled the first one, we do not show another
76   // right afterwards.
77   if ((PinRequestWidget::Get() && !security_token_request_in_progress_) ||
78       request_canceled_) {
79     std::move(request.pin_ui_closed_callback).Run();
80     return false;
81   }
82 
83   on_pin_submitted_ = std::move(request.pin_entered_callback);
84   on_canceled_by_user_ = std::move(request.pin_ui_closed_callback);
85 
86   // If this is a new request, open a PIN widget. Otherwise, just update the
87   // existing widget.
88   if (!security_token_request_in_progress_) {
89     security_token_request_in_progress_ = true;
90     PinRequest pin_request;
91     pin_request.on_pin_request_done = base::DoNothing::Once<bool>();
92     pin_request.pin_keyboard_always_enabled = true;
93     pin_request.extra_dimmer = true;
94     pin_request.title = GetTitle();
95     pin_request.description = GetDescription();
96     pin_request.accessible_title = GetAccessibleTitle();
97     PinRequestWidget::Show(std::move(pin_request), this);
98   }
99 
100   PinRequestWidget::Get()->ClearInput();
101   PinRequestWidget::Get()->SetPinInputEnabled(request.enable_user_input);
102 
103   if (request.error_label == chromeos::security_token_pin::ErrorLabel::kNone) {
104     PinRequestWidget::Get()->UpdateState(PinRequestViewState::kNormal,
105                                          GetTitle(), GetDescription());
106   } else {
107     PinRequestWidget::Get()->UpdateState(
108         PinRequestViewState::kError,
109         /*title=*/
110         chromeos::security_token_pin::GenerateErrorMessage(
111             request.error_label, request.attempts_left,
112             request.enable_user_input),
113         /*description=*/base::string16());
114   }
115   return true;
116 }
117 
ClosePinUi()118 void SecurityTokenRequestController::ClosePinUi() {
119   if (!security_token_request_in_progress_)
120     return;
121 
122   if (PinRequestWidget::Get()) {
123     PinRequestWidget::Get()->Close(false);  // Parameter will be ignored.
124   }
125   on_pin_submitted_.Reset();
126   on_canceled_by_user_.Reset();
127   security_token_request_in_progress_ = false;
128 }
129 
130 }  // namespace ash
131