1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use distant_net::{AuthChallengeFn, AuthErrorFn, AuthInfoFn, AuthVerifyFn, AuthVerifyKind};
use log::*;
use std::io;
pub struct DistantManagerClientConfig {
pub on_challenge: Box<AuthChallengeFn>,
pub on_verify: Box<AuthVerifyFn>,
pub on_info: Box<AuthInfoFn>,
pub on_error: Box<AuthErrorFn>,
}
impl DistantManagerClientConfig {
pub fn with_empty_prompts() -> Self {
Self::with_prompts(|_| Ok("".to_string()), |_| Ok("".to_string()))
}
pub fn with_prompts<PP, PT>(password_prompt: PP, text_prompt: PT) -> Self
where
PP: Fn(&str) -> io::Result<String> + Send + Sync + 'static,
PT: Fn(&str) -> io::Result<String> + Send + Sync + 'static,
{
Self {
on_challenge: Box::new(move |questions, _extra| {
trace!("[manager client] on_challenge({questions:?}, {_extra:?})");
let mut answers = Vec::new();
for question in questions.iter() {
let mut lines = question.text.split('\n').collect::<Vec<_>>();
let line = lines.pop().unwrap();
for line in lines.into_iter() {
eprintln!("{}", line);
}
let answer = password_prompt(line).unwrap_or_default();
answers.push(answer);
}
answers
}),
on_verify: Box::new(move |kind, text| {
trace!("[manager client] on_verify({kind}, {text})");
match kind {
AuthVerifyKind::Host => {
eprintln!("{}", text);
match text_prompt("Enter [y/N]> ") {
Ok(answer) => {
trace!("Verify? Answer = '{answer}'");
matches!(answer.trim(), "y" | "Y" | "yes" | "YES")
}
Err(x) => {
error!("Failed verification: {x}");
false
}
}
}
x => {
error!("Unsupported verify kind: {x}");
false
}
}
}),
on_info: Box::new(|text| {
trace!("[manager client] on_info({text})");
println!("{}", text);
}),
on_error: Box::new(|kind, text| {
trace!("[manager client] on_error({kind}, {text})");
eprintln!("{}: {}", kind, text);
}),
}
}
}