use super::{ AuthMethodHandler, Challenge, ChallengeResponse, Error, Info, Verification, VerificationKind, VerificationResponse, }; use async_trait::async_trait; use log::*; use std::io; /// Blocking implementation of [`AuthMethodHandler`] that uses prompts to communicate challenge & /// verification requests, receiving responses to relay back. pub struct PromptAuthMethodHandler { text_prompt: T, password_prompt: U, } impl PromptAuthMethodHandler { pub fn new(text_prompt: T, password_prompt: U) -> Self { Self { text_prompt, password_prompt, } } } #[async_trait] impl AuthMethodHandler for PromptAuthMethodHandler where T: Fn(&str) -> io::Result + Send + Sync + 'static, U: Fn(&str) -> io::Result + Send + Sync + 'static, { async fn on_challenge(&mut self, challenge: Challenge) -> io::Result { trace!("on_challenge({challenge:?})"); let mut answers = Vec::new(); for question in challenge.questions.iter() { // Contains all prompt lines including same line let mut lines = question.text.split('\n').collect::>(); // Line that is prompt on same line as answer let line = lines.pop().unwrap(); // Go ahead and display all other lines for line in lines.into_iter() { eprintln!("{}", line); } // Get an answer from user input, or use a blank string as an answer // if we fail to get input from the user let answer = (self.password_prompt)(line).unwrap_or_default(); answers.push(answer); } Ok(ChallengeResponse { answers }) } async fn on_verification( &mut self, verification: Verification, ) -> io::Result { trace!("on_verify({verification:?})"); match verification.kind { VerificationKind::Host => { eprintln!("{}", verification.text); let answer = (self.text_prompt)("Enter [y/N]> ")?; trace!("Verify? Answer = '{answer}'"); Ok(VerificationResponse { valid: matches!(answer.trim(), "y" | "Y" | "yes" | "YES"), }) } x => { error!("Unsupported verify kind: {x}"); Ok(VerificationResponse { valid: false }) } } } async fn on_info(&mut self, info: Info) -> io::Result<()> { trace!("on_info({info:?})"); println!("{}", info.text); Ok(()) } async fn on_error(&mut self, error: Error) -> io::Result<()> { trace!("on_error({error:?})"); eprintln!("{}: {}", error.kind, error.text); Ok(()) } }