mirror of
https://github.com/herdrdev/herdr.git
synced 2026-09-23 08:01:09 +00:00
* feat(windows): support remote attach to unix hosts * fix(remote): preserve unix bridge behavior
90 lines
2.4 KiB
Rust
90 lines
2.4 KiB
Rust
mod attach;
|
|
#[cfg(unix)]
|
|
mod host_unix;
|
|
|
|
pub(crate) use attach::*;
|
|
#[cfg(unix)]
|
|
pub(crate) use host_unix::run_remote_client_bridge;
|
|
|
|
#[cfg(windows)]
|
|
pub(crate) fn run_remote_client_bridge() -> std::io::Result<()> {
|
|
Err(std::io::Error::other(
|
|
"remote Windows hosts are not supported yet",
|
|
))
|
|
}
|
|
|
|
pub(crate) fn print_remote_error_hint(err: &std::io::Error, target: &str) {
|
|
if is_remote_auth_error(err) {
|
|
eprintln!(
|
|
"hint: verify SSH access first with `{}`.",
|
|
ssh_check_command(target)
|
|
);
|
|
eprintln!(
|
|
"hint: if your SSH key has a passphrase, load it into ssh-agent with `ssh-add` before running `herdr --remote`."
|
|
);
|
|
}
|
|
}
|
|
|
|
fn is_remote_auth_error(err: &std::io::Error) -> bool {
|
|
let message = err.to_string();
|
|
message.contains("Permission denied")
|
|
&& (message.contains("(publickey")
|
|
|| message.contains("(keyboard-interactive")
|
|
|| message.contains("(password"))
|
|
}
|
|
|
|
fn ssh_check_command(target: &str) -> String {
|
|
format!("ssh {}", shell_quote(target))
|
|
}
|
|
|
|
fn shell_quote(value: &str) -> String {
|
|
if !value.is_empty()
|
|
&& value.chars().all(|ch| {
|
|
ch.is_ascii_alphanumeric()
|
|
|| matches!(
|
|
ch,
|
|
'@' | '%' | '_' | '+' | '=' | ':' | ',' | '.' | '/' | '-'
|
|
)
|
|
})
|
|
{
|
|
return value.to_string();
|
|
}
|
|
|
|
format!("'{}'", value.replace('\'', "'\\''"))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn remote_auth_error_matches_ssh_auth_denied() {
|
|
let err = std::io::Error::other(
|
|
"remote platform detection failed: user@host: Permission denied (publickey).",
|
|
);
|
|
|
|
assert!(is_remote_auth_error(&err));
|
|
}
|
|
|
|
#[test]
|
|
fn remote_auth_error_matches_keyboard_interactive_denied() {
|
|
let err = std::io::Error::other(
|
|
"remote server status failed: user@host: Permission denied (keyboard-interactive).",
|
|
);
|
|
|
|
assert!(is_remote_auth_error(&err));
|
|
}
|
|
|
|
#[test]
|
|
fn remote_auth_error_ignores_non_auth_errors() {
|
|
let err = std::io::Error::other("remote platform detection failed: unsupported platform");
|
|
|
|
assert!(!is_remote_auth_error(&err));
|
|
}
|
|
|
|
#[test]
|
|
fn ssh_check_command_quotes_remote_target() {
|
|
assert_eq!(ssh_check_command("host name"), "ssh 'host name'");
|
|
}
|
|
}
|