windows: Use nc-esque ssh askpass auth for remoting (#39646)

This lets us avoid storing user PW in ZED_ASKPASS_PASSWORD env var.
Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz
2025-10-07 09:48:03 +02:00
committed by GitHub
parent 963204c99d
commit 41ac6a8764
6 changed files with 212 additions and 159 deletions
+18 -15
View File
@@ -70,14 +70,13 @@ impl From<settings::SshConnection> for SshConnectionOptions {
}
}
#[derive(Clone)]
struct SshSocket {
connection_options: SshConnectionOptions,
#[cfg(not(target_os = "windows"))]
socket_path: PathBuf,
socket_path: std::path::PathBuf,
envs: HashMap<String, String>,
#[cfg(target_os = "windows")]
password: askpass::EncryptedPassword,
_proxy: askpass::PasswordProxy,
}
macro_rules! shell_script {
@@ -343,16 +342,17 @@ impl SshRemoteConnection {
}
#[cfg(not(target_os = "windows"))]
let socket = SshSocket::new(connection_options, socket_path)?;
let socket = SshSocket::new(connection_options, socket_path).await?;
#[cfg(target_os = "windows")]
let socket = SshSocket::new(
connection_options,
&temp_dir,
askpass
.get_password()
.or_else(|| askpass::EncryptedPassword::try_from("").ok())
.context("Failed to fetch askpass password")?,
)?;
cx.background_executor().clone(),
)
.await?;
drop(askpass);
let ssh_platform = socket.platform().await?;
@@ -659,7 +659,7 @@ impl SshRemoteConnection {
impl SshSocket {
#[cfg(not(target_os = "windows"))]
fn new(options: SshConnectionOptions, socket_path: PathBuf) -> Result<Self> {
async fn new(options: SshConnectionOptions, socket_path: PathBuf) -> Result<Self> {
Ok(Self {
connection_options: options,
envs: HashMap::default(),
@@ -668,21 +668,26 @@ impl SshSocket {
}
#[cfg(target_os = "windows")]
fn new(
async fn new(
options: SshConnectionOptions,
temp_dir: &TempDir,
password: askpass::EncryptedPassword,
executor: gpui::BackgroundExecutor,
) -> Result<Self> {
let askpass_script = temp_dir.path().join("askpass.bat");
std::fs::write(&askpass_script, "@ECHO OFF\necho %ZED_SSH_ASKPASS%")?;
let mut envs = HashMap::default();
let get_password =
move |_| Task::ready(std::ops::ControlFlow::Continue(Ok(password.clone())));
let _proxy = askpass::PasswordProxy::new(get_password, executor).await?;
envs.insert("SSH_ASKPASS_REQUIRE".into(), "force".into());
envs.insert("SSH_ASKPASS".into(), askpass_script.display().to_string());
envs.insert(
"SSH_ASKPASS".into(),
_proxy.script_path().as_ref().display().to_string(),
);
Ok(Self {
connection_options: options,
envs,
password,
_proxy,
})
}
@@ -736,14 +741,12 @@ impl SshSocket {
#[cfg(target_os = "windows")]
fn ssh_options<'a>(&self, command: &'a mut process::Command) -> &'a mut process::Command {
use askpass::ProcessExt;
command
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.args(self.connection_options.additional_args())
.envs(self.envs.clone())
.encrypted_env("ZED_SSH_ASKPASS", self.password.clone())
}
// On Windows, we need to use `SSH_ASKPASS` to provide the password to ssh.