From 13b1b90a8366d02f5929e673e227ec1a4d09f534 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 14 Jun 2023 07:34:03 -0700 Subject: [PATCH] tunnel: fix keyring panic on Linux (#185066) tunnel: fix keyring panic on Linxu Fixes #184792 Reported on https://github.com/hwchen/keyring-rs/issues/132 --- cli/src/auth.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/cli/src/auth.rs b/cli/src/auth.rs index d9089940730..604b1a6ced7 100644 --- a/cli/src/auth.rs +++ b/cli/src/auth.rs @@ -20,7 +20,7 @@ use async_trait::async_trait; use chrono::{DateTime, Duration, Utc}; use gethostname::gethostname; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use std::{cell::Cell, fmt::Display, path::PathBuf, sync::Arc}; +use std::{cell::Cell, fmt::Display, path::PathBuf, sync::Arc, thread}; use tokio::time::sleep; use tunnels::{ contracts::PROD_FIRST_PARTY_APP_ID, @@ -210,6 +210,48 @@ const KEYCHAIN_ENTRY_LIMIT: usize = 128 * 1024; const CONTINUE_MARKER: &str = ""; +/// Implementation that wraps the KeyringStorage on Linux to avoid +/// https://github.com/hwchen/keyring-rs/issues/132 +struct ThreadKeyringStorage { + s: Option, +} + +impl ThreadKeyringStorage { + fn thread_op(&mut self, f: Fn) -> R + where + Fn: 'static + Send + FnOnce(&mut KeyringStorage) -> R, + R: 'static + Send, + { + let mut s = self.s.take().unwrap(); + let handler = thread::spawn(move || (f(&mut s), s)); + let (r, s) = handler.join().unwrap(); + self.s = Some(s); + r + } +} + +impl Default for ThreadKeyringStorage { + fn default() -> Self { + Self { + s: Some(KeyringStorage::default()), + } + } +} + +impl StorageImplementation for ThreadKeyringStorage { + fn read(&mut self) -> Result, WrappedError> { + self.thread_op(|s| s.read()) + } + + fn store(&mut self, value: StoredCredential) -> Result<(), WrappedError> { + self.thread_op(move |s| s.store(value)) + } + + fn clear(&mut self) -> Result<(), WrappedError> { + self.thread_op(|s| s.clear()) + } +} + #[derive(Default)] struct KeyringStorage { // keywring storage can be split into multiple entries due to entry length limits @@ -325,7 +367,10 @@ impl Auth { return op(s); } + #[cfg(not(target_os = "linux"))] let mut keyring_storage = KeyringStorage::default(); + #[cfg(target_os = "linux")] + let mut keyring_storage = ThreadKeyringStorage::default(); let mut file_storage = FileStorage(PersistedState::new(self.file_storage_path.clone())); let keyring_storage_result = match std::env::var("VSCODE_CLI_USE_FILE_KEYCHAIN") {