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 203 204 205 206 207
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CERTIFICATE_PROVIDER_PIN_DIALOG_MANAGER_H_
#define CHROME_BROWSER_CERTIFICATE_PROVIDER_PIN_DIALOG_MANAGER_H_
#include <map>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/certificate_provider/security_token_pin_dialog_host.h"
#include "chrome/browser/certificate_provider/security_token_pin_dialog_host_popup_impl.h"
#include "chromeos/components/security_token_pin/constants.h"
#include "components/account_id/account_id.h"
namespace chromeos {
// Manages the state of the dialog that requests the PIN from user. Used by the
// extensions that need to request the PIN. Implemented as requirement for
// crbug.com/612886
class PinDialogManager final {
public:
enum class RequestPinResult {
kSuccess,
kInvalidId,
kOtherFlowInProgress,
kDialogDisplayedAlready,
};
enum class StopPinRequestResult {
kSuccess,
kNoActiveDialog,
kNoUserInput,
};
using RequestPinCallback =
base::OnceCallback<void(const std::string& user_input)>;
using StopPinRequestCallback = base::OnceClosure;
PinDialogManager();
PinDialogManager(const PinDialogManager&) = delete;
PinDialogManager& operator=(const PinDialogManager&) = delete;
~PinDialogManager();
// Stores internally the |signRequestId| along with current timestamp.
void AddSignRequestId(
const std::string& extension_id,
int sign_request_id,
const std::optional<AccountId>& authenticating_user_account_id);
// Removes the specified sign request, aborting both the current and the
// future PIN dialogs related to it.
void RemoveSignRequest(const std::string& extension_id, int sign_request_id);
// Returns the number of pending sign requests stored in sign_requests_
int StoredSignRequestsForTesting() const;
// Creates and displays a new PIN dialog, or reuses the old dialog with just
// updating the parameters if active one exists.
// |extension_id| - the ID of the extension requesting the dialog.
// |extension_name| - the name of the extension requesting the dialog.
// |sign_request_id| - the ID given by Chrome when the extension was asked to
// sign the data. It should be a valid, not expired ID at the time the
// extension is requesting PIN the first time.
// |code_type| - the type of input requested: either "PIN" or "PUK".
// |error_label| - the error template to be displayed inside the dialog. If
// |kNone|, no error is displayed.
// |attempts_left| - the number of attempts the user has to try the code. It
// is informational only, and enforced on Chrome side only in case it's
// zero. In that case the textfield is disabled and the user can't provide
// any input to extension. If -1 the textfield from the dialog is enabled
// but no information about the attepts left is not given to the user.
// |callback| - used to notify about the user input in the text_field from the
// dialog.
// Returns |kSuccess| if the dialog is displayed and extension owns it.
// Otherwise the specific error is returned.
RequestPinResult RequestPin(const std::string& extension_id,
const std::string& extension_name,
int sign_request_id,
security_token_pin::CodeType code_type,
security_token_pin::ErrorLabel error_label,
int attempts_left,
RequestPinCallback callback);
// Updates the existing dialog with the error message. Returns whether the
// provided |extension_id| matches the extension owning the active dialog.
// When it is, the |callback| will be executed once the UI is completed (e.g.,
// the dialog with the error message is closed by the user).
StopPinRequestResult StopPinRequestWithError(
const std::string& extension_id,
security_token_pin::ErrorLabel error_label,
StopPinRequestCallback callback);
// Returns whether the last PIN dialog from this extension was closed by the
// user.
bool LastPinDialogClosed(const std::string& extension_id) const;
// Called when extension calls the stopPinRequest method. The active dialog is
// closed if the |extension_id| matches the |active_dialog_extension_id_|.
// Returns whether the dialog was closed.
bool CloseDialog(const std::string& extension_id);
// Resets the manager data related to the extension.
void ExtensionUnloaded(const std::string& extension_id);
// Dynamically adds the dialog host that can be used by this instance for
// showing new dialogs. There may be multiple hosts added, in which case the
// most recently added is used. Before any hosts have been added, the default
// (popup-based) host is used.
void AddPinDialogHost(SecurityTokenPinDialogHost* pin_dialog_host);
// Removes the previously added dialog host. If a dialog is still opened in
// this host, closes it beforehand.
void RemovePinDialogHost(SecurityTokenPinDialogHost* pin_dialog_host);
SecurityTokenPinDialogHostPopupImpl* default_dialog_host_for_testing() {
return &default_dialog_host_;
}
private:
struct SignRequestState {
SignRequestState(
base::Time begin_time,
const std::optional<AccountId>& authenticating_user_account_id);
SignRequestState(const SignRequestState&);
SignRequestState& operator=(const SignRequestState&);
~SignRequestState();
base::Time begin_time;
std::optional<AccountId> authenticating_user_account_id;
};
// Holds information related to the currently opened PIN dialog.
struct ActiveDialogState {
ActiveDialogState(SecurityTokenPinDialogHost* host,
const std::string& extension_id,
const std::string& extension_name,
int sign_request_id,
security_token_pin::CodeType code_type);
~ActiveDialogState();
// Remember the host that was used to open the active dialog, as new hosts
// could have been added since the dialog was opened, but we want to
// continue calling the same host when dealing with the same active dialog.
const raw_ptr<SecurityTokenPinDialogHost> host;
const std::string extension_id;
const std::string extension_name;
const int sign_request_id;
const security_token_pin::CodeType code_type;
RequestPinCallback request_pin_callback;
StopPinRequestCallback stop_pin_request_callback;
};
using ExtensionNameRequestIdPair = std::pair<std::string, int>;
// Returns the sign request state for the given key, or null if not found.
SignRequestState* FindSignRequestState(const std::string& extension_id,
int sign_request_id);
// The callback that gets invoked once the user sends some input into the PIN
// dialog.
void OnPinEntered(const std::string& user_input);
// The callback that gets invoked once the PIN dialog gets closed.
void OnPinDialogClosed();
// Returns the dialog host that should own the new dialog. Currently returns
// the most recently added dialog host (falling back to the default one when
// no host has been added).
SecurityTokenPinDialogHost* GetHostForNewDialog();
// Closes the active dialog, if there's any, and runs the necessary callbacks.
void CloseActiveDialog();
// Tells whether user closed the last request PIN dialog issued by an
// extension. The extension_id is the key and value is true if user closed the
// dialog. Used to determine if the limit of dialogs rejected by the user has
// been exceeded.
std::unordered_map<std::string, bool> last_response_closed_;
// The map from extension_id and an active sign request id to the state of the
// request.
std::map<ExtensionNameRequestIdPair, SignRequestState> sign_requests_;
SecurityTokenPinDialogHostPopupImpl default_dialog_host_;
// The list of dynamically added dialog hosts, in the same order as they were
// added.
std::vector<raw_ptr<SecurityTokenPinDialogHost, VectorExperimental>>
added_dialog_hosts_;
// There can be only one active dialog to request the PIN at any point of
// time.
std::optional<ActiveDialogState> active_dialog_state_;
base::WeakPtrFactory<PinDialogManager> weak_factory_{this};
};
} // namespace chromeos
#endif // CHROME_BROWSER_CERTIFICATE_PROVIDER_PIN_DIALOG_MANAGER_H_
|