horto_os_ui_shared/remote/
askpass.rs1use crate::error::{HortoError, Result};
4use std::path::PathBuf;
5
6pub fn resolve_askpass() -> Result<PathBuf> {
15 if let Ok(ask) = std::env::var("SSH_ASKPASS") {
16 let ask = ask.trim();
17 if !ask.is_empty() {
18 return Ok(PathBuf::from(ask));
19 }
20 }
21 for name in [
22 "ssh-askpass",
23 "x11-ssh-askpass",
24 "gnome-ssh-askpass",
25 "ksshaskpass",
26 "lxqt-openssh-askpass",
27 ] {
28 if let Ok(path) = which::which(name) {
29 return Ok(path);
30 }
31 }
32 Err(HortoError::msg(
33 "No system password helper found for SSH login",
34 ))
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use crate::remote::ENV_LOCK;
41 use std::fs;
42 use std::os::unix::fs::PermissionsExt;
43
44 #[test]
45 fn resolve_askpass_skips_blank_env() {
46 let _g = ENV_LOCK.lock().expect("env lock");
47 std::env::set_var("SSH_ASKPASS", " ");
48 let old_path = std::env::var_os("PATH");
49 std::env::set_var("PATH", "");
50 let err = resolve_askpass().unwrap_err().to_string();
51 match old_path {
52 Some(p) => std::env::set_var("PATH", p),
53 None => std::env::remove_var("PATH"),
54 }
55 std::env::remove_var("SSH_ASKPASS");
56 assert!(err.contains("No system password helper found"));
57 }
58
59 #[test]
60 fn resolve_askpass_errors_when_unset_and_no_path() {
61 let _g = ENV_LOCK.lock().expect("env lock");
62 std::env::remove_var("SSH_ASKPASS");
63 let old_path = std::env::var_os("PATH");
64 std::env::set_var("PATH", "");
65 let err = resolve_askpass().unwrap_err().to_string();
66 match old_path {
67 Some(p) => std::env::set_var("PATH", p),
68 None => std::env::remove_var("PATH"),
69 }
70 assert!(err.contains("No system password helper found"));
71 }
72
73 #[test]
74 fn resolve_askpass_prefers_env() {
75 let _g = ENV_LOCK.lock().expect("env lock");
76 let dir = tempfile::tempdir().expect("tmpdir");
77 let script = dir.path().join("askpass.sh");
78 fs::write(&script, "#!/bin/sh\n").expect("write");
79 let mut perms = fs::metadata(&script).expect("meta").permissions();
80 perms.set_mode(0o755);
81 fs::set_permissions(&script, perms).expect("chmod");
82 std::env::set_var("SSH_ASKPASS", &script);
83 let got = resolve_askpass().expect("resolve");
84 std::env::remove_var("SSH_ASKPASS");
85 assert_eq!(got, script);
86 }
87
88 #[test]
89 fn resolve_askpass_finds_binary_on_path() {
90 let _g = ENV_LOCK.lock().expect("env lock");
91 std::env::remove_var("SSH_ASKPASS");
92 let dir = tempfile::tempdir().expect("tmpdir");
93 let bin = dir.path().join("ssh-askpass");
94 fs::write(&bin, "#!/bin/sh\n").expect("write");
95 let mut perms = fs::metadata(&bin).expect("meta").permissions();
96 perms.set_mode(0o755);
97 fs::set_permissions(&bin, perms).expect("chmod");
98 let old_path = std::env::var_os("PATH");
99 std::env::set_var("PATH", dir.path());
100 let got = resolve_askpass().expect("resolve");
101 match old_path {
102 Some(p) => std::env::set_var("PATH", p),
103 None => std::env::remove_var("PATH"),
104 }
105 assert_eq!(got, bin);
106 }
107}