mirror of
https://github.com/wez/wezterm.git
synced 2024-12-28 07:55:03 +03:00
ssh: allow a number of auth retries
Rather than just a single attempt at each mechanism, let's allow up to 3 loops, each time trying all supported mechanisms. This helps for the case where the user makes a typo with their password, and should also help for more complicated auth setups where succeeding with one mechanism may not be sufficient. While testing this out I noticed that were deferring closing the OS level window until after the entire auth attempt, so I added some logic to proactively close the prompt windows. In the longer term I'd like all related prompts to render in the same window for improved cognotive continuity.
This commit is contained in:
parent
970e4a8e64
commit
b59893fd9f
@ -2454,9 +2454,12 @@ impl TermWindow {
|
||||
|
||||
let (top, mut lines) = tab.renderer().get_lines(stable_row..stable_row + 1);
|
||||
let new_highlight = if top == stable_row {
|
||||
let line = &mut lines[0];
|
||||
if let Some(cell) = line.cells().get(x) {
|
||||
cell.attrs().hyperlink.as_ref().cloned()
|
||||
if let Some(line) = lines.get_mut(0) {
|
||||
if let Some(cell) = line.cells().get(x) {
|
||||
cell.attrs().hyperlink.as_ref().cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -252,6 +252,11 @@ impl Mux {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kill_window(&self, window_id: WindowId) {
|
||||
let mut windows = self.windows.borrow_mut();
|
||||
windows.remove(&window_id);
|
||||
}
|
||||
|
||||
pub fn get_window(&self, window_id: WindowId) -> Option<Ref<Window>> {
|
||||
if !self.windows.borrow().contains_key(&window_id) {
|
||||
return None;
|
||||
|
40
src/ssh.rs
40
src/ssh.rs
@ -281,28 +281,34 @@ pub fn ssh_connect(remote_address: &str, username: &str) -> anyhow::Result<ssh2:
|
||||
|
||||
let methods: HashSet<&str> = sess.auth_methods(&username)?.split(',').collect();
|
||||
|
||||
if !sess.authenticated() && methods.contains("publickey") {
|
||||
if let Err(err) = sess.userauth_agent(&username) {
|
||||
log::info!("while attempting agent auth: {}", err);
|
||||
for _ in 0..3 {
|
||||
if sess.authenticated() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !sess.authenticated() && methods.contains("password") {
|
||||
let pass = password_prompt("", "Password", username, &remote_address)
|
||||
.ok_or_else(|| anyhow!("password entry was cancelled"))?;
|
||||
if let Err(err) = sess.userauth_password(username, &pass) {
|
||||
log::error!("while attempting password auth: {}", err);
|
||||
if !sess.authenticated() && methods.contains("publickey") {
|
||||
if let Err(err) = sess.userauth_agent(&username) {
|
||||
log::info!("while attempting agent auth: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !sess.authenticated() && methods.contains("keyboard-interactive") {
|
||||
let mut prompt = Prompt {
|
||||
username,
|
||||
remote_address: &remote_address,
|
||||
};
|
||||
if !sess.authenticated() && methods.contains("password") {
|
||||
let pass = password_prompt("", "Password", username, &remote_address)
|
||||
.ok_or_else(|| anyhow!("password entry was cancelled"))?;
|
||||
if let Err(err) = sess.userauth_password(username, &pass) {
|
||||
log::error!("while attempting password auth: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = sess.userauth_keyboard_interactive(&username, &mut prompt) {
|
||||
log::error!("while attempting keyboard-interactive auth: {}", err);
|
||||
if !sess.authenticated() && methods.contains("keyboard-interactive") {
|
||||
let mut prompt = Prompt {
|
||||
username,
|
||||
remote_address: &remote_address,
|
||||
};
|
||||
|
||||
if let Err(err) = sess.userauth_keyboard_interactive(&username, &mut prompt) {
|
||||
log::error!("while attempting keyboard-interactive auth: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,7 +403,7 @@ pub async fn run<
|
||||
render_rx: Receiver<Vec<Change>>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> anyhow::Result<WindowId> {
|
||||
let mux = Mux::get().unwrap();
|
||||
|
||||
// TODO: make a singleton
|
||||
@ -431,16 +431,30 @@ pub async fn run<
|
||||
let gui = front_end().unwrap();
|
||||
gui.spawn_new_window(&fontconfig, &tab, window_id)?;
|
||||
|
||||
Ok(())
|
||||
Ok(window_id)
|
||||
}
|
||||
|
||||
let window_id: WindowId = promise::spawn::spawn_into_main_thread(async move {
|
||||
register_tab(input_tx, render_rx, width, height).await
|
||||
})
|
||||
.await
|
||||
.unwrap_or_else(|| bail!("task panicked or was cancelled"))?;
|
||||
|
||||
let result = promise::spawn::spawn_into_new_thread(move || f(tw_term))
|
||||
.await
|
||||
.unwrap_or_else(|| bail!("task panicked or was cancelled"));
|
||||
|
||||
// Since we're typically called with an outstanding Activity token active,
|
||||
// the dead status of the tab will be ignored until after the activity
|
||||
// resolves. In the case of SSH where (currently!) several prompts may
|
||||
// be shown in succession, we don't want to leave lingering dead windows
|
||||
// on the screen so let's ask the mux to kill off our window now.
|
||||
promise::spawn::spawn_into_main_thread(async move {
|
||||
register_tab(input_tx, render_rx, width, height).await.ok();
|
||||
let mux = Mux::get().unwrap();
|
||||
mux.kill_window(window_id);
|
||||
});
|
||||
|
||||
promise::spawn::spawn_into_new_thread(move || f(tw_term))
|
||||
.await
|
||||
.unwrap_or_else(|| bail!("task panicked or was cancelled"))
|
||||
result
|
||||
}
|
||||
|
||||
pub fn message_box_ok(message: &str) {
|
||||
|
Loading…
Reference in New Issue
Block a user