Function get_input

Source
pub fn get_input(
    prompt: &str,
    default_value: Option<&str>,
    echo: bool,
    verify: bool,
) -> Option<String>
Expand description

A utility function that will prompt the user for input via the console/tty.

prompt is the text to show to the user. default_value can be used to pre-set the answer, allowing the user to simply press enter.

echo, if true, means to show the user’s answer on the screen as they type it. If false, means to conceal it.

verify, if true, will ask the user for their input twice in order to confirm that they provided the same text both times. This is useful when creating a password and echo == false.

Examples found in repository?
examples/whoami.rs (line 38)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
fn prompt(prompt: &str, echo: bool) -> SshResult<String> {
    get_input(prompt, None, echo, false).ok_or_else(|| Error::Fatal("reading password".to_string()))
}

fn prompt_stdin(prompt: &str) -> SshResult<String> {
    eprintln!("{}", prompt);
    let mut input = String::new();
    let _ = std::io::stdin().read_line(&mut input)?;
    Ok(input.trim().to_string())
}

fn authenticate(sess: &Session, user_name: Option<&str>) -> SshResult<()> {
    match sess.userauth_none(user_name)? {
        AuthStatus::Success => return Ok(()),
        _ => {}
    }

    loop {
        let auth_methods = sess.userauth_list(user_name)?;

        if auth_methods.contains(AuthMethods::PUBLIC_KEY) {
            match sess.userauth_public_key_auto(None, None)? {
                AuthStatus::Success => return Ok(()),
                _ => {}
            }
        }

        if auth_methods.contains(AuthMethods::INTERACTIVE) {
            loop {
                match sess.userauth_keyboard_interactive(None, None)? {
                    AuthStatus::Success => return Ok(()),
                    AuthStatus::Info => {
                        let info = sess.userauth_keyboard_interactive_info()?;
                        if !info.instruction.is_empty() {
                            eprintln!("{}", info.instruction);
                        }
                        let mut answers = vec![];
                        for p in &info.prompts {
                            answers.push(prompt(&p.prompt, p.echo)?);
                        }
                        sess.userauth_keyboard_interactive_set_answers(&answers)?;

                        continue;
                    }
                    AuthStatus::Denied => {
                        break;
                    }
                    status => {
                        return Err(Error::Fatal(format!(
                            "interactive auth status: {:?}",
                            status
                        )))
                    }
                }
            }
        }

        if auth_methods.contains(AuthMethods::PASSWORD) {
            let pw = prompt("Password: ", false)?;

            match sess.userauth_password(user_name, Some(&pw))? {
                AuthStatus::Success => return Ok(()),
                status => return Err(Error::Fatal(format!("password auth status: {:?}", status))),
            }
        }

        return Err(Error::Fatal("unhandled auth case".to_string()));
    }
}

fn main() -> SshResult<()> {
    let sess = Session::new()?;
    sess.set_auth_callback(|prompt, echo, verify, identity| {
        let prompt = match identity {
            Some(ident) => format!("{} ({}): ", prompt, ident),
            None => prompt.to_string(),
        };
        get_input(&prompt, None, echo, verify)
            .ok_or_else(|| Error::Fatal("reading password".to_string()))
    });

    sess.set_option(SshOption::Hostname("localhost".to_string()))?;
    // sess.set_option(SshOption::LogLevel(LogLevel::Packet))?;
    sess.options_parse_config(None)?;
    sess.connect()?;
    eprintln!(
        "using {} as user name for authentication",
        sess.get_user_name()?
    );
    verify_known_hosts(&sess)?;

    authenticate(&sess, None)?;

    let channel = sess.new_channel()?;
    channel.open_session()?;
    channel.request_exec("whoami")?;
    channel.send_eof()?;

    let mut stdout = String::new();
    channel.stdout().read_to_string(&mut stdout)?;

    eprintln!("whoami -> {}", stdout);

    let res = channel.get_exit_status();
    eprintln!("exit status: {:?}", res);

    Ok(())
}