blob: a4cfe880f82dbe479a95a51b0cf1a74238aa2c53 [file] [log] [blame]
igorcovbb898fb2016-12-01 16:07:561// Copyright 2016 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 "chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h"
6
Maksim Ivanov73dfec32019-08-01 22:43:127#include "base/bind.h"
8#include "base/logging.h"
igorcovbb898fb2016-12-01 16:07:569
10namespace chromeos {
11
12// Define timeout for issued sign_request_id.
Maksim Ivanov86866b72019-07-25 02:15:0613constexpr base::TimeDelta kSignRequestIdTimeout =
14 base::TimeDelta::FromMinutes(10);
igorcovbb898fb2016-12-01 16:07:5615
Maksim Ivanov86866b72019-07-25 02:15:0616PinDialogManager::PinDialogManager() = default;
igorcovbb898fb2016-12-01 16:07:5617
Maksim Ivanov73dfec32019-08-01 22:43:1218PinDialogManager::~PinDialogManager() = default;
igorcovbb898fb2016-12-01 16:07:5619
20void PinDialogManager::AddSignRequestId(const std::string& extension_id,
21 int sign_request_id) {
22 ExtensionNameRequestIdPair key(extension_id, sign_request_id);
23 // Cache the ID with current timestamp.
Maksim Ivanov86866b72019-07-25 02:15:0624 sign_request_times_[key] = base::Time::Now();
igorcovbb898fb2016-12-01 16:07:5625}
26
Maksim Ivanov86866b72019-07-25 02:15:0627PinDialogManager::RequestPinResult PinDialogManager::RequestPin(
igorcovbb898fb2016-12-01 16:07:5628 const std::string& extension_id,
29 const std::string& extension_name,
30 int sign_request_id,
Maksim Ivanov73dfec32019-08-01 22:43:1231 PinCodeType code_type,
32 PinErrorLabel error_label,
igorcovbb898fb2016-12-01 16:07:5633 int attempts_left,
Maksim Ivanov86866b72019-07-25 02:15:0634 RequestPinCallback callback) {
Maksim Ivanov73dfec32019-08-01 22:43:1235 DCHECK_GE(attempts_left, -1);
36 const bool accept_input = (attempts_left != 0);
37
38 // Start from sanity checks, as the extension might have issued this call
39 // incorrectly.
40 if (active_dialog_state_) {
41 // The active dialog exists already, so we need to make sure it belongs to
42 // the same extension and the user submitted some input.
43 if (extension_id != active_dialog_state_->extension_id)
Maksim Ivanov86866b72019-07-25 02:15:0644 return RequestPinResult::kOtherFlowInProgress;
Maksim Ivanov73dfec32019-08-01 22:43:1245 if (active_dialog_state_->request_pin_callback ||
46 active_dialog_state_->stop_pin_request_callback) {
47 // Extension requests a PIN without having received any input from its
48 // previous request. Reject the new request.
Maksim Ivanov86866b72019-07-25 02:15:0649 return RequestPinResult::kDialogDisplayedAlready;
Maksim Ivanov73dfec32019-08-01 22:43:1250 }
51 } else {
52 // Check the validity of sign_request_id
53 const ExtensionNameRequestIdPair key(extension_id, sign_request_id);
54 if (sign_request_times_.find(key) == sign_request_times_.end())
55 return RequestPinResult::kInvalidId;
56 const base::Time current_time = base::Time::Now();
57 if (current_time - sign_request_times_[key] > kSignRequestIdTimeout)
58 return RequestPinResult::kInvalidId;
igorcovbb898fb2016-12-01 16:07:5659
Maksim Ivanov73dfec32019-08-01 22:43:1260 // A new dialog will be opened, so initialize the related internal state.
61 active_dialog_state_.emplace(&default_dialog_host_, extension_id,
62 extension_name, code_type);
igorcovbb898fb2016-12-01 16:07:5663 }
64
Maksim Ivanov73dfec32019-08-01 22:43:1265 active_dialog_state_->request_pin_callback = std::move(callback);
66 active_dialog_state_->host->ShowSecurityTokenPinDialog(
67 extension_name, code_type, accept_input, error_label, attempts_left,
68 base::BindOnce(&PinDialogManager::OnPinEntered,
69 weak_factory_.GetWeakPtr()),
70 base::BindOnce(&PinDialogManager::OnPinDialogClosed,
71 weak_factory_.GetWeakPtr()));
igorcovbb898fb2016-12-01 16:07:5672
Maksim Ivanov86866b72019-07-25 02:15:0673 return RequestPinResult::kSuccess;
igorcovbb898fb2016-12-01 16:07:5674}
75
Maksim Ivanov86866b72019-07-25 02:15:0676PinDialogManager::StopPinRequestResult
Maksim Ivanov73dfec32019-08-01 22:43:1277PinDialogManager::StopPinRequestWithError(const std::string& extension_id,
78 PinErrorLabel error_label,
79 StopPinRequestCallback callback) {
80 DCHECK_NE(error_label, PinErrorLabel::kNone);
81
82 // Perform sanity checks, as the extension might have issued this call
83 // incorrectly.
84 if (!active_dialog_state_ ||
85 active_dialog_state_->extension_id != extension_id) {
Maksim Ivanov86866b72019-07-25 02:15:0686 return StopPinRequestResult::kNoActiveDialog;
igorcovbb898fb2016-12-01 16:07:5687 }
Maksim Ivanov73dfec32019-08-01 22:43:1288 if (active_dialog_state_->request_pin_callback ||
89 active_dialog_state_->stop_pin_request_callback) {
Maksim Ivanov86866b72019-07-25 02:15:0690 return StopPinRequestResult::kNoUserInput;
Maksim Ivanov73dfec32019-08-01 22:43:1291 }
igorcovbb898fb2016-12-01 16:07:5692
Maksim Ivanov73dfec32019-08-01 22:43:1293 active_dialog_state_->stop_pin_request_callback = std::move(callback);
94 active_dialog_state_->host->ShowSecurityTokenPinDialog(
95 active_dialog_state_->extension_name, active_dialog_state_->code_type,
96 /*enable_user_input=*/false, error_label,
Maksim Ivanov86866b72019-07-25 02:15:0697 /*attempts_left=*/-1,
Maksim Ivanov73dfec32019-08-01 22:43:1298 base::BindOnce(&PinDialogManager::OnPinEntered,
99 weak_factory_.GetWeakPtr()),
100 base::BindOnce(&PinDialogManager::OnPinDialogClosed,
101 weak_factory_.GetWeakPtr()));
102
Maksim Ivanov86866b72019-07-25 02:15:06103 return StopPinRequestResult::kSuccess;
igorcovbb898fb2016-12-01 16:07:56104}
105
Maksim Ivanov86866b72019-07-25 02:15:06106bool PinDialogManager::LastPinDialogClosed(
107 const std::string& extension_id) const {
108 auto iter = last_response_closed_.find(extension_id);
109 return iter != last_response_closed_.end() && iter->second;
igorcovbb898fb2016-12-01 16:07:56110}
111
112bool PinDialogManager::CloseDialog(const std::string& extension_id) {
Maksim Ivanov73dfec32019-08-01 22:43:12113 // Perform sanity checks, as the extension might have issued this call
114 // incorrectly.
115 if (!active_dialog_state_ ||
116 extension_id != active_dialog_state_->extension_id) {
igorcovbb898fb2016-12-01 16:07:56117 LOG(ERROR) << "StopPinRequest called by unexpected extension: "
118 << extension_id;
119 return false;
120 }
121
Maksim Ivanov73dfec32019-08-01 22:43:12122 active_dialog_state_->host->CloseSecurityTokenPinDialog();
123
124 // The active dialog state should have been cleared by OnPinDialogClosed().
125 DCHECK(!active_dialog_state_);
126
127 last_response_closed_[extension_id] = true;
igorcovbb898fb2016-12-01 16:07:56128 return true;
129}
130
131void PinDialogManager::ExtensionUnloaded(const std::string& extension_id) {
Maksim Ivanov73dfec32019-08-01 22:43:12132 if (active_dialog_state_ &&
133 active_dialog_state_->extension_id == extension_id) {
igorcovbb898fb2016-12-01 16:07:56134 CloseDialog(extension_id);
Maksim Ivanov73dfec32019-08-01 22:43:12135 }
igorcovbb898fb2016-12-01 16:07:56136
137 last_response_closed_[extension_id] = false;
138
139 for (auto it = sign_request_times_.cbegin();
140 it != sign_request_times_.cend();) {
Maksim Ivanov86866b72019-07-25 02:15:06141 if (it->first.first == extension_id)
igorcovbb898fb2016-12-01 16:07:56142 sign_request_times_.erase(it++);
Maksim Ivanov86866b72019-07-25 02:15:06143 else
igorcovbb898fb2016-12-01 16:07:56144 ++it;
igorcovbb898fb2016-12-01 16:07:56145 }
146}
147
Maksim Ivanov73dfec32019-08-01 22:43:12148PinDialogManager::ActiveDialogState::ActiveDialogState(
149 SecurityTokenPinDialogHost* host,
150 const std::string& extension_id,
151 const std::string& extension_name,
152 PinCodeType code_type)
153 : host(host),
154 extension_id(extension_id),
155 extension_name(extension_name),
156 code_type(code_type) {}
Maksim Ivanovab8e8582019-08-01 21:49:13157
Maksim Ivanov73dfec32019-08-01 22:43:12158PinDialogManager::ActiveDialogState::~ActiveDialogState() = default;
159
160void PinDialogManager::OnPinEntered(const std::string& user_input) {
161 DCHECK(!active_dialog_state_->stop_pin_request_callback);
162 last_response_closed_[active_dialog_state_->extension_id] = false;
163 if (active_dialog_state_->request_pin_callback)
164 std::move(active_dialog_state_->request_pin_callback).Run(user_input);
Maksim Ivanovab8e8582019-08-01 21:49:13165}
166
167void PinDialogManager::OnPinDialogClosed() {
Maksim Ivanov73dfec32019-08-01 22:43:12168 DCHECK(!active_dialog_state_->request_pin_callback ||
169 !active_dialog_state_->stop_pin_request_callback);
Maksim Ivanovab8e8582019-08-01 21:49:13170
Maksim Ivanov73dfec32019-08-01 22:43:12171 last_response_closed_[active_dialog_state_->extension_id] = true;
172 if (active_dialog_state_->request_pin_callback) {
173 std::move(active_dialog_state_->request_pin_callback)
174 .Run(/*user_input=*/std::string());
175 }
176 if (active_dialog_state_->stop_pin_request_callback)
177 std::move(active_dialog_state_->stop_pin_request_callback).Run();
178 active_dialog_state_.reset();
Maksim Ivanovab8e8582019-08-01 21:49:13179}
180
igorcovbb898fb2016-12-01 16:07:56181} // namespace chromeos