feat(ssh): auto-fill ssh config parameters in auth form

Resolve SSH host parameters in auth forms and CLI connections while preserving explicit user, bookmark, and parsed alias values. Continue forwarding SSH config files for HostName and other SSH options, and document the precedence in English and Chinese.

Closes #441
This commit is contained in:
Christian Visintin
2026-09-01 12:52:10 +02:00
parent 7434c51063
commit d99c76b43c
15 changed files with 548 additions and 69 deletions
+74 -1
View File
@@ -5,6 +5,18 @@
use ssh2_config::{ParseRule, SshConfig};
/// The standard port used when an SSH configuration does not define one.
const DEFAULT_SSH_PORT: u16 = 22;
/// Connection parameters resolved from an SSH host configuration.
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct SshHostParams {
/// Resolved SSH port.
pub(crate) port: u16,
/// Resolved SSH username, when configured.
pub(crate) username: Option<String>,
}
/// Parses an OpenSSH-style config file into an `ssh2_config::SshConfig`.
pub fn parse_ssh2_config(path: &str) -> Result<SshConfig, String> {
use std::fs::File;
@@ -18,10 +30,23 @@ pub fn parse_ssh2_config(path: &str) -> Result<SshConfig, String> {
.map_err(|e| format!("Failed to parse ssh2 config: {e}"))
}
/// Resolves SSH connection parameters for a host from the startup-parsed configuration.
pub(crate) fn resolve_ssh_host_params(config: Option<&SshConfig>, host: &str) -> SshHostParams {
let params = config.map(|config| config.query(host));
SshHostParams {
port: params
.as_ref()
.and_then(|params| params.port)
.unwrap_or(DEFAULT_SSH_PORT),
username: params.and_then(|params| params.user),
}
}
#[cfg(test)]
mod test {
use crate::utils::ssh::parse_ssh2_config;
use super::{SshHostParams, parse_ssh2_config, resolve_ssh_host_params};
use crate::utils::test_helpers;
#[test]
@@ -53,4 +78,52 @@ Host test
.is_ok()
);
}
#[test]
fn ssh_host_params_should_resolve_exact_and_wildcard_hosts() {
let ssh_config_file = test_helpers::create_sample_file_with_content(
r#"
Host exact-host
Port 2222
User exact-user
Host *.example.com
Port 2200
User wildcard-user
"#,
);
let config = parse_ssh2_config(&ssh_config_file.path().to_string_lossy())
.expect("test SSH configuration should parse");
assert_eq!(
resolve_ssh_host_params(Some(&config), "exact-host"),
SshHostParams {
port: 2222,
username: Some("exact-user".to_string()),
}
);
assert_eq!(
resolve_ssh_host_params(Some(&config), "server.example.com"),
SshHostParams {
port: 2200,
username: Some("wildcard-user".to_string()),
}
);
}
#[test]
fn ssh_host_params_should_default_when_configuration_has_no_values() {
let ssh_config_file =
test_helpers::create_sample_file_with_content("Host unconfigured-host\n");
let config = parse_ssh2_config(&ssh_config_file.path().to_string_lossy())
.expect("test SSH configuration should parse");
assert_eq!(
resolve_ssh_host_params(Some(&config), "unconfigured-host"),
SshHostParams {
port: 22,
username: None,
}
);
}
}