askpass: Fix ssh auth not updating entered password on windows (#47755)

Lukas Wirth created

Release Notes:

- Fixed mistyping the ssh password in the askpass prompt on windows
locking you out of retyping the correct one

Change summary

crates/askpass/src/askpass.rs | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

Detailed changes

crates/askpass/src/askpass.rs 🔗

@@ -73,17 +73,18 @@ impl AskPassDelegate {
 
 pub struct AskPassSession {
     #[cfg(target_os = "windows")]
-    secret: std::sync::Arc<OnceLock<EncryptedPassword>>,
+    secret: std::sync::Arc<std::sync::Mutex<Option<EncryptedPassword>>>,
     askpass_task: PasswordProxy,
     askpass_opened_rx: Option<oneshot::Receiver<()>>,
     askpass_kill_master_rx: Option<oneshot::Receiver<()>>,
     executor: BackgroundExecutor,
 }
 
-#[cfg(not(target_os = "windows"))]
-const ASKPASS_SCRIPT_NAME: &str = "askpass.sh";
-#[cfg(target_os = "windows")]
-const ASKPASS_SCRIPT_NAME: &str = "askpass.ps1";
+const ASKPASS_SCRIPT_NAME: &str = if cfg!(target_os = "windows") {
+    "askpass.ps1"
+} else {
+    "askpass.sh"
+};
 
 impl AskPassSession {
     /// This will create a new AskPassSession.
@@ -91,7 +92,8 @@ impl AskPassSession {
     #[must_use]
     pub async fn new(executor: BackgroundExecutor, mut delegate: AskPassDelegate) -> Result<Self> {
         #[cfg(target_os = "windows")]
-        let secret = std::sync::Arc::new(OnceLock::new());
+        let secret = std::sync::Arc::new(std::sync::Mutex::new(None));
+
         let (askpass_opened_tx, askpass_opened_rx) = oneshot::channel::<()>();
 
         let askpass_opened_tx = Arc::new(Mutex::new(Some(askpass_opened_tx)));
@@ -99,11 +101,11 @@ impl AskPassSession {
         let (askpass_kill_master_tx, askpass_kill_master_rx) = oneshot::channel::<()>();
         let kill_tx = Arc::new(Mutex::new(Some(askpass_kill_master_tx)));
 
-        #[cfg(target_os = "windows")]
-        let askpass_secret = secret.clone();
         let get_password = {
             let executor = executor.clone();
 
+            #[cfg(target_os = "windows")]
+            let askpass_secret = secret.clone();
             move |prompt| {
                 let prompt = delegate.ask_password(prompt);
                 let kill_tx = kill_tx.clone();
@@ -117,7 +119,7 @@ impl AskPassSession {
                     if let Some(password) = prompt.await {
                         #[cfg(target_os = "windows")]
                         {
-                            _ = askpass_secret.set(password.clone());
+                            askpass_secret.lock().unwrap().replace(password.clone());
                         }
                         ControlFlow::Continue(Ok(password))
                     } else {
@@ -172,7 +174,7 @@ impl AskPassSession {
     /// This will return the password that was last set by the askpass script.
     #[cfg(target_os = "windows")]
     pub fn get_password(&self) -> Option<EncryptedPassword> {
-        self.secret.get().cloned()
+        self.secret.lock().ok()?.clone()
     }
 
     pub fn script_path(&self) -> impl AsRef<OsStr> {