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}