summaryrefslogtreecommitdiff
path: root/vendor/dialoguer/src/prompts/password.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/dialoguer/src/prompts/password.rs')
-rw-r--r--vendor/dialoguer/src/prompts/password.rs194
1 files changed, 194 insertions, 0 deletions
diff --git a/vendor/dialoguer/src/prompts/password.rs b/vendor/dialoguer/src/prompts/password.rs
new file mode 100644
index 0000000..7327605
--- /dev/null
+++ b/vendor/dialoguer/src/prompts/password.rs
@@ -0,0 +1,194 @@
+use std::io;
+
+use crate::{
+ theme::{SimpleTheme, TermThemeRenderer, Theme},
+ validate::PasswordValidator,
+};
+
+use console::Term;
+use zeroize::Zeroizing;
+
+type PasswordValidatorCallback<'a> = Box<dyn Fn(&String) -> Option<String> + 'a>;
+
+/// Renders a password input prompt.
+///
+/// ## Example usage
+///
+/// ```rust,no_run
+/// # fn test() -> Result<(), Box<std::error::Error>> {
+/// use dialoguer::Password;
+///
+/// let password = Password::new().with_prompt("New Password")
+/// .with_confirmation("Confirm password", "Passwords mismatching")
+/// .interact()?;
+/// println!("Length of the password is: {}", password.len());
+/// # Ok(()) } fn main() { test().unwrap(); }
+/// ```
+pub struct Password<'a> {
+ prompt: String,
+ report: bool,
+ theme: &'a dyn Theme,
+ allow_empty_password: bool,
+ confirmation_prompt: Option<(String, String)>,
+ validator: Option<PasswordValidatorCallback<'a>>,
+}
+
+impl Default for Password<'static> {
+ fn default() -> Password<'static> {
+ Self::new()
+ }
+}
+
+impl Password<'static> {
+ /// Creates a password input prompt.
+ pub fn new() -> Password<'static> {
+ Self::with_theme(&SimpleTheme)
+ }
+}
+
+impl<'a> Password<'a> {
+ /// Sets the password input prompt.
+ pub fn with_prompt<S: Into<String>>(&mut self, prompt: S) -> &mut Self {
+ self.prompt = prompt.into();
+ self
+ }
+
+ /// Indicates whether to report confirmation after interaction.
+ ///
+ /// The default is to report.
+ pub fn report(&mut self, val: bool) -> &mut Self {
+ self.report = val;
+ self
+ }
+
+ /// Enables confirmation prompting.
+ pub fn with_confirmation<A, B>(&mut self, prompt: A, mismatch_err: B) -> &mut Self
+ where
+ A: Into<String>,
+ B: Into<String>,
+ {
+ self.confirmation_prompt = Some((prompt.into(), mismatch_err.into()));
+ self
+ }
+
+ /// Allows/Disables empty password.
+ ///
+ /// By default this setting is set to false (i.e. password is not empty).
+ pub fn allow_empty_password(&mut self, allow_empty_password: bool) -> &mut Self {
+ self.allow_empty_password = allow_empty_password;
+ self
+ }
+
+ /// Registers a validator.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use dialoguer::Password;
+ /// let password: String = Password::new()
+ /// .with_prompt("Enter password")
+ /// .validate_with(|input: &String| -> Result<(), &str> {
+ /// if input.len() > 8 {
+ /// Ok(())
+ /// } else {
+ /// Err("Password must be longer than 8")
+ /// }
+ /// })
+ /// .interact()
+ /// .unwrap();
+ /// ```
+ pub fn validate_with<V>(&mut self, validator: V) -> &mut Self
+ where
+ V: PasswordValidator + 'a,
+ V::Err: ToString,
+ {
+ let old_validator_func = self.validator.take();
+
+ self.validator = Some(Box::new(move |value: &String| -> Option<String> {
+ if let Some(old) = &old_validator_func {
+ if let Some(err) = old(value) {
+ return Some(err);
+ }
+ }
+
+ match validator.validate(value) {
+ Ok(()) => None,
+ Err(err) => Some(err.to_string()),
+ }
+ }));
+
+ self
+ }
+
+ /// Enables user interaction and returns the result.
+ ///
+ /// If the user confirms the result is `true`, `false` otherwise.
+ /// The dialog is rendered on stderr.
+ pub fn interact(&self) -> io::Result<String> {
+ self.interact_on(&Term::stderr())
+ }
+
+ /// Like `interact` but allows a specific terminal to be set.
+ pub fn interact_on(&self, term: &Term) -> io::Result<String> {
+ let mut render = TermThemeRenderer::new(term, self.theme);
+ render.set_prompts_reset_height(false);
+
+ loop {
+ let password = Zeroizing::new(self.prompt_password(&mut render, &self.prompt)?);
+
+ if let Some(ref validator) = self.validator {
+ if let Some(err) = validator(&password) {
+ render.error(&err)?;
+ continue;
+ }
+ }
+
+ if let Some((ref prompt, ref err)) = self.confirmation_prompt {
+ let pw2 = Zeroizing::new(self.prompt_password(&mut render, prompt)?);
+
+ if *password != *pw2 {
+ render.error(err)?;
+ continue;
+ }
+ }
+
+ render.clear()?;
+
+ if self.report {
+ render.password_prompt_selection(&self.prompt)?;
+ }
+ term.flush()?;
+
+ return Ok((*password).clone());
+ }
+ }
+
+ fn prompt_password(&self, render: &mut TermThemeRenderer, prompt: &str) -> io::Result<String> {
+ loop {
+ render.password_prompt(prompt)?;
+ render.term().flush()?;
+
+ let input = render.term().read_secure_line()?;
+
+ render.add_line();
+
+ if !input.is_empty() || self.allow_empty_password {
+ return Ok(input);
+ }
+ }
+ }
+}
+
+impl<'a> Password<'a> {
+ /// Creates a password input prompt with a specific theme.
+ pub fn with_theme(theme: &'a dyn Theme) -> Self {
+ Self {
+ prompt: "".into(),
+ report: true,
+ theme,
+ allow_empty_password: false,
+ confirmation_prompt: None,
+ validator: None,
+ }
+ }
+}