inquire/prompts/password/mod.rs
1mod action;
2mod config;
3mod prompt;
4#[cfg(test)]
5#[cfg(feature = "crossterm")]
6mod test;
7
8pub use action::*;
9
10use crate::{
11 config::get_configuration,
12 error::{InquireError, InquireResult},
13 formatter::StringFormatter,
14 prompts::prompt::Prompt,
15 terminal::get_default_terminal,
16 ui::{Backend, PasswordBackend, RenderConfig},
17 validator::StringValidator,
18};
19
20use self::prompt::PasswordPrompt;
21
22/// Display modes of the text input of a password prompt.
23#[derive(Copy, Clone, Debug, PartialEq, Eq)]
24pub enum PasswordDisplayMode {
25 /// Password text input is not rendered at all, no indication of input.
26 Hidden,
27
28 /// Characters of the password text input are rendered marked as different
29 /// characters, such as asterisks. These characters are configured in the
30 /// render config.
31 Masked,
32
33 /// Password text input is fully rendered as a normal input, just like
34 /// [Text](crate::Text) prompts.
35 Full,
36}
37
38/// Prompt meant for secretive text inputs.
39///
40/// By default, the password prompt behaves like a standard one you'd see in common CLI applications: the user has no UI indicators about the state of the current input. They do not know how many characters they typed, or which character they typed, with no option to display the current text input.
41///
42/// However, you can still customize these and other behaviors if you wish:
43/// - **Standard display mode**: Set the display mode of the text input among hidden, masked and full via the `PasswordDisplayMode` enum.
44/// - Hidden: default behavior, no UI indicators.
45/// - Masked: behaves like a normal text input, except that all characters of the input are masked to a special character, which is `'*'` by default but can be customized via `RenderConfig`.
46/// - Full: behaves like a normal text input, no modifications.
47/// - **Toggle display mode**: When enabling this feature by calling the `with_display_toggle_enabled()` method, you allow the user to toggle between the standard display mode set and the full display mode.
48/// - If you have set the standard display mode to hidden (which is also the default) or masked, the user can press `Ctrl+R` to change the display mode to `Full`, and `Ctrl+R` again to change it back to the standard one.
49/// - Obviously, if you have set the standard display mode to `Full`, pressing `Ctrl+R` won't cause any changes.
50/// - **Confirmation**: By default, the password will have a confirmation flow where the user will be asked for the input twice and the two responses will be compared. If they differ, an error message is shown and the user is prompted again.
51/// - By default, a "Confirmation:" message is shown for the confirmation prompts, but this can be modified by setting a custom confirmation message only shown the second time, using the `with_custom_confirmation_message()` method.
52/// - If confirmation is not desired, it can be turned off using the `without_confirmation()` method.
53/// - **Help message**: Message displayed at the line below the prompt.
54/// - **Formatter**: Custom formatter in case you need to pre-process the user input before showing it as the final answer.
55/// - By default, it prints eight asterisk characters: `********`.
56/// - **Validators**: Custom validators to make sure a given submitted input pass the specified requirements, e.g. not allowing empty inputs or requiring special characters.
57/// - No validators are on by default.
58///
59/// Remember that for CLI applications it is standard to not allow use any display modes other than `Hidden` and to not allow the user to see the text input in any way. _Use the customization options at your discretion_.
60///
61/// # Example
62///
63/// ```no_run
64/// use inquire::{validator::{StringValidator, Validation}, Password, PasswordDisplayMode};
65///
66/// let validator = |input: &str| if input.chars().count() < 10 {
67/// Ok(Validation::Invalid("Keys must have at least 10 characters.".into()))
68/// } else {
69/// Ok(Validation::Valid)
70/// };
71///
72/// let name = Password::new("Encryption Key:")
73/// .with_display_toggle_enabled()
74/// .with_display_mode(PasswordDisplayMode::Hidden)
75/// .with_custom_confirmation_message("Encryption Key (confirm):")
76/// .with_custom_confirmation_error_message("The keys don't match.")
77/// .with_validator(validator)
78/// .with_formatter(&|_| String::from("Input received"))
79/// .with_help_message("It is recommended to generate a new one only for this purpose")
80/// .prompt();
81///
82/// match name {
83/// Ok(_) => println!("This doesn't look like a key."),
84/// Err(_) => println!("An error happened when asking for your key, try again later."),
85/// }
86/// ```
87#[derive(Clone)]
88pub struct Password<'a> {
89 /// Message to be presented to the user.
90 pub message: &'a str,
91
92 /// Message to be presented to the user when confirming the input.
93 pub custom_confirmation_message: Option<&'a str>,
94
95 /// Error to be presented to the user when password confirmation fails.
96 pub custom_confirmation_error_message: Option<&'a str>,
97
98 /// Help message to be presented to the user.
99 pub help_message: Option<&'a str>,
100
101 /// Function that formats the user input and presents it to the user as the final rendering of the prompt.
102 pub formatter: StringFormatter<'a>,
103
104 /// How the password input is displayed to the user.
105 pub display_mode: PasswordDisplayMode,
106
107 /// Whether to allow the user to toggle the display of the current password input by pressing the Ctrl+R hotkey.
108 pub enable_display_toggle: bool,
109
110 /// Whether to ask for input twice to see if the provided passwords are the same.
111 pub enable_confirmation: bool,
112
113 /// Collection of validators to apply to the user input.
114 ///
115 /// Validators are executed in the order they are stored, stopping at and displaying to the user
116 /// only the first validation error that might appear.
117 ///
118 /// The possible error is displayed to the user one line above the prompt.
119 pub validators: Vec<Box<dyn StringValidator>>,
120
121 /// RenderConfig to apply to the rendered interface.
122 ///
123 /// Note: The default render config considers if the NO_COLOR environment variable
124 /// is set to decide whether to render the colored config or the empty one.
125 ///
126 /// When overriding the config in a prompt, NO_COLOR is no longer considered and your
127 /// config is treated as the only source of truth. If you want to customize colors
128 /// and still support NO_COLOR, you will have to do this on your end.
129 pub render_config: RenderConfig<'a>,
130}
131
132impl<'a> Password<'a> {
133 /// Default formatter, set to always display `"********"` regardless of input length.
134 pub const DEFAULT_FORMATTER: StringFormatter<'a> = &|_| String::from("********");
135
136 /// Default validators added to the [Password] prompt, none.
137 pub const DEFAULT_VALIDATORS: Vec<Box<dyn StringValidator>> = vec![];
138
139 /// Default help message.
140 pub const DEFAULT_HELP_MESSAGE: Option<&'a str> = None;
141
142 /// Default value for the allow display toggle variable.
143 pub const DEFAULT_ENABLE_DISPLAY_TOGGLE: bool = false;
144
145 /// Default value for the enable confirmation variable.
146 pub const DEFAULT_ENABLE_CONFIRMATION: bool = true;
147
148 /// Default password display mode.
149 pub const DEFAULT_DISPLAY_MODE: PasswordDisplayMode = PasswordDisplayMode::Hidden;
150
151 /// Creates a [Password] with the provided message and default options.
152 pub fn new(message: &'a str) -> Self {
153 Self {
154 message,
155 custom_confirmation_message: None,
156 custom_confirmation_error_message: None,
157 enable_confirmation: Self::DEFAULT_ENABLE_CONFIRMATION,
158 enable_display_toggle: Self::DEFAULT_ENABLE_DISPLAY_TOGGLE,
159 display_mode: Self::DEFAULT_DISPLAY_MODE,
160 help_message: Self::DEFAULT_HELP_MESSAGE,
161 formatter: Self::DEFAULT_FORMATTER,
162 validators: Self::DEFAULT_VALIDATORS,
163 render_config: get_configuration(),
164 }
165 }
166
167 /// Sets the help message of the prompt.
168 pub fn with_help_message(mut self, message: &'a str) -> Self {
169 self.help_message = Some(message);
170 self
171 }
172
173 /// Sets the flag to enable display toggling.
174 pub fn with_display_toggle_enabled(mut self) -> Self {
175 self.enable_display_toggle = true;
176 self
177 }
178
179 /// Disables the confirmation step of the prompt.
180 pub fn without_confirmation(mut self) -> Self {
181 self.enable_confirmation = false;
182 self
183 }
184
185 /// Sets the prompt message when asking for the password confirmation.
186 pub fn with_custom_confirmation_message(mut self, message: &'a str) -> Self {
187 self.custom_confirmation_message.replace(message);
188 self
189 }
190
191 /// Sets the prompt error message when password confirmation fails.
192 pub fn with_custom_confirmation_error_message(mut self, message: &'a str) -> Self {
193 self.custom_confirmation_error_message.replace(message);
194 self
195 }
196
197 /// Sets the standard display mode for the prompt.
198 pub fn with_display_mode(mut self, mode: PasswordDisplayMode) -> Self {
199 self.display_mode = mode;
200 self
201 }
202
203 /// Sets the formatter.
204 pub fn with_formatter(mut self, formatter: StringFormatter<'a>) -> Self {
205 self.formatter = formatter;
206 self
207 }
208
209 /// Adds a validator to the collection of validators. You might want to use this feature
210 /// in case you need to limit the user to specific choices, such as requiring
211 /// special characters in the password.
212 ///
213 /// Validators are executed in the order they are stored, stopping at and displaying to the user
214 /// only the first validation error that might appear.
215 ///
216 /// The possible error is displayed to the user one line above the prompt.
217 pub fn with_validator<V>(mut self, validator: V) -> Self
218 where
219 V: StringValidator + 'static,
220 {
221 self.validators.push(Box::new(validator));
222 self
223 }
224
225 /// Adds the validators to the collection of validators in the order they are given.
226 ///
227 /// Validators are executed in the order they are stored, stopping at and displaying to the user
228 /// only the first validation error that might appear.
229 ///
230 /// The possible error is displayed to the user one line above the prompt.
231 pub fn with_validators(mut self, validators: &[Box<dyn StringValidator>]) -> Self {
232 for validator in validators {
233 #[allow(suspicious_double_ref_op)]
234 self.validators.push(validator.clone());
235 }
236 self
237 }
238
239 /// Sets the provided color theme to this prompt.
240 ///
241 /// Note: The default render config considers if the NO_COLOR environment variable
242 /// is set to decide whether to render the colored config or the empty one.
243 ///
244 /// When overriding the config in a prompt, NO_COLOR is no longer considered and your
245 /// config is treated as the only source of truth. If you want to customize colors
246 /// and still support NO_COLOR, you will have to do this on your end.
247 pub fn with_render_config(mut self, render_config: RenderConfig<'a>) -> Self {
248 self.render_config = render_config;
249 self
250 }
251
252 /// Parses the provided behavioral and rendering options and prompts
253 /// the CLI user for input according to the defined rules.
254 ///
255 /// This method is intended for flows where the user skipping/cancelling
256 /// the prompt - by pressing ESC - is considered normal behavior. In this case,
257 /// it does not return `Err(InquireError::OperationCanceled)`, but `Ok(None)`.
258 ///
259 /// Meanwhile, if the user does submit an answer, the method wraps the return
260 /// type with `Some`.
261 pub fn prompt_skippable(self) -> InquireResult<Option<String>> {
262 match self.prompt() {
263 Ok(answer) => Ok(Some(answer)),
264 Err(InquireError::OperationCanceled) => Ok(None),
265 Err(err) => Err(err),
266 }
267 }
268
269 /// Parses the provided behavioral and rendering options and prompts
270 /// the CLI user for input according to the defined rules.
271 pub fn prompt(self) -> InquireResult<String> {
272 let (input_reader, terminal) = get_default_terminal()?;
273 let mut backend = Backend::new(input_reader, terminal, self.render_config)?;
274 self.prompt_with_backend(&mut backend)
275 }
276
277 pub(crate) fn prompt_with_backend<B: PasswordBackend>(
278 self,
279 backend: &mut B,
280 ) -> InquireResult<String> {
281 PasswordPrompt::from(self).prompt(backend)
282 }
283}