use std::path::Path; use auth_git2::Prompter; use inquire::{InquireError, PasswordDisplayMode}; use crate::Config; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Inquirer<'a>(pub &'a Config); fn config_value(git_config: &git2::Config, name: &str) -> Option { git_config .get_entry(name) .ok() .and_then(|entry| entry.value().map(|entry| entry.to_string())) } fn prompt_secret(message: &str) -> Result { inquire::Password::new(message) .without_confirmation() .with_display_mode(PasswordDisplayMode::Masked) .prompt() } impl Prompter for Inquirer<'_> { fn prompt_username_password( &mut self, url: &str, git_config: &git2::Config, ) -> Option<(String, String)> { let username = self .0 .username_for_url(url) .cloned() .or_else(|| config_value(git_config, "autosave.username")); let password = self .0 .password_for_url(url) .cloned() .or_else(|| config_value(git_config, "autosave.password")); if let Some(username) = username && let Some(password) = password { return Some((username, password)); } println!("Authenticating to {url}"); let username = inquire::prompt_text("Username:").ok()?; let password = prompt_secret("Password:").ok()?; Some((username, password)) } fn prompt_password( &mut self, username: &str, url: &str, git_config: &git2::Config, ) -> Option { let password = self .0 .password_for_url(url) .cloned() .or_else(|| config_value(git_config, "autosave.password")); if let Some(password) = password { return Some(password); } println!("Authenticating to {url}"); prompt_secret(&format!("Password for {username}:")).ok() } fn prompt_ssh_key_passphrase( &mut self, private_key_path: &Path, git_config: &git2::Config, ) -> Option { let password = self .0 .passphrase_for_key(private_key_path) .cloned() .or_else(|| config_value(git_config, "autosave.password")); if let Some(password) = password { return Some(password); } prompt_secret(&format!( "Passphrase for {}:", private_key_path.to_string_lossy() )) .ok() } }