From 28668e1b2c994b2e5d6b25bbf5b6781eb7659972 Mon Sep 17 00:00:00 2001 From: Lukylix Date: Wed, 19 Jun 2024 14:08:10 +0200 Subject: [PATCH 1/7] Fix askpass pipe on windows --- DEVELOPMENT.md | 2 +- crates/gitbutler-git/Cargo.toml | 12 +- .../src/bin/askpass/windows-pipe.rs | 124 ++++++++++++++++++ .../gitbutler-git/src/bin/askpass/windows.rs | 37 ++---- .../src/executor/tokio/windows.rs | 23 ++-- 5 files changed, 156 insertions(+), 42 deletions(-) create mode 100644 crates/gitbutler-git/src/bin/askpass/windows-pipe.rs diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 5fc97481c..44ccc5efb 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -203,7 +203,7 @@ This paragraph is about crosscompilation to x86_64-MSVC from ARM Windows, a configuration typical for people with Apple Silicon and Parallels VMs, which only allow ARM Windows to be used. -The `winapi` dependency on `gitbutler-git` doesn't currently compile on ARM, +The `windows` dependency on `gitbutler-git` doesn't currently compile on ARM, which means cross-compilation to x86-64 is required to workaround that. Besides, most users will probably still be on INTEL machines, making this capability a common requirement. diff --git a/crates/gitbutler-git/Cargo.toml b/crates/gitbutler-git/Cargo.toml index 2f07a3dbc..4e7649a58 100644 --- a/crates/gitbutler-git/Cargo.toml +++ b/crates/gitbutler-git/Cargo.toml @@ -44,10 +44,16 @@ sysinfo = "0.30.12" nix = { version = "0.29.0", features = ["process", "socket", "user"] } [target."cfg(windows)".dependencies] -winapi = { version = "0.3.9", features = ["winbase", "namedpipeapi"] } +windows = { version = "0.57.0", features = [ + "Win32", + "Win32_System", + "Win32_System_Pipes", + "Win32_Storage", + "Win32_Storage_FileSystem", + "Win32_Security", + "Win32_System_IO", +] } tokio = { workspace = true, optional = true, features = ["sync"] } -# synchronous named pipes for the askpass utility -windows-named-pipe = "0.1.0" [lints.clippy] all = "deny" diff --git a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs new file mode 100644 index 000000000..a77b5e22c --- /dev/null +++ b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs @@ -0,0 +1,124 @@ +use std::ffi::OsString; +use std::io::{self, Read, Write}; +use std::os::windows::ffi::OsStrExt; +use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use std::path::Path; +use windows::core::PWSTR; +use windows::Win32::Foundation::{ + ERROR_PIPE_NOT_CONNECTED, GENERIC_READ, GENERIC_WRITE, HANDLE, WIN32_ERROR, +}; +use windows::Win32::Storage::FileSystem::{ + CreateFileW, FlushFileBuffers, ReadFile, WriteFile, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, + FILE_SHARE_WRITE, OPEN_EXISTING, +}; +use windows::Win32::System::Pipes::{WaitNamedPipeW, NMPWAIT_USE_DEFAULT_WAIT}; + +#[derive(Debug)] +struct Handle { + inner: HANDLE, +} + +unsafe impl Send for Handle {} +unsafe impl Sync for Handle {} + +#[derive(Debug)] +pub struct Pipe { + handle: Handle, +} + +impl Pipe { + pub fn connect(path: &Path) -> io::Result { + let mut os_str: OsString = path.as_os_str().into(); + os_str.push("\x00"); + let mut wide_path: Vec = os_str.encode_wide().collect(); + + let pwstr_path = PWSTR(wide_path.as_mut_ptr()); + let _ = unsafe { WaitNamedPipeW(pwstr_path, NMPWAIT_USE_DEFAULT_WAIT) }; + let handle_res = unsafe { + CreateFileW( + pwstr_path, + GENERIC_READ.0 | GENERIC_WRITE.0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + None, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + None, + ) + }; + + match handle_res { + Ok(handle) => Ok(Pipe { + handle: Handle { inner: handle }, + }), + Err(err) => Err(io::Error::from_raw_os_error(err.code().0)), + } + } + + pub fn get_handle(&self) -> HANDLE { + self.handle.inner + } +} + +impl Drop for Pipe { + fn drop(&mut self) { + let _ = unsafe { FlushFileBuffers(self.handle.inner) }; + } +} + +impl Read for Pipe { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut bytes_read = 0u32; + let res = unsafe { ReadFile(self.handle.inner, Some(buf), Some(&mut bytes_read), None) }; + match res { + Ok(_) => Ok(bytes_read as usize), + Err(err) => match WIN32_ERROR::from_error(&err) { + Some(ERROR_PIPE_NOT_CONNECTED) => Ok(0), + _ => Err(io::Error::from_raw_os_error(err.code().0)), + }, + } + } +} + +impl Write for Pipe { + fn write(&mut self, buf: &[u8]) -> io::Result { + let mut bytes_written = 0u32; + + let res = + unsafe { WriteFile(self.handle.inner, Some(buf), Some(&mut bytes_written), None) }; + + match res { + Ok(_) => Ok(bytes_written as usize), + Err(err) => Err(io::Error::from_raw_os_error(err.code().0)), + } + } + + fn flush(&mut self) -> io::Result<()> { + let res = unsafe { FlushFileBuffers(self.handle.inner) }; + + match res { + Ok(_) => Ok(()), + Err(err) => Err(io::Error::from_raw_os_error(err.code().0)), + } + } +} + +impl AsRawHandle for Pipe { + fn as_raw_handle(&self) -> RawHandle { + self.handle.inner.0 as RawHandle + } +} + +impl IntoRawHandle for Pipe { + fn into_raw_handle(self) -> RawHandle { + self.handle.inner.0 as RawHandle + } +} + +impl FromRawHandle for Pipe { + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + let handle = HANDLE(handle as isize); + Pipe { + handle: Handle { inner: handle }, + } + } +} diff --git a/crates/gitbutler-git/src/bin/askpass/windows.rs b/crates/gitbutler-git/src/bin/askpass/windows.rs index fb473f88b..916a20bd3 100644 --- a/crates/gitbutler-git/src/bin/askpass/windows.rs +++ b/crates/gitbutler-git/src/bin/askpass/windows.rs @@ -3,10 +3,13 @@ use std::{ os::windows::io::{AsRawHandle, FromRawHandle}, time::Duration, }; -use windows_named_pipe::PipeStream; +use windows::Win32::System::Pipes::SetNamedPipeHandleState; +#[path = "windows-pipe.rs"] +mod windows_pipe; +use windows_pipe::Pipe; -pub fn establish(sock_path: &str) -> PipeStream { - PipeStream::connect(sock_path).unwrap() +pub fn establish(sock_path: &str) -> Pipe { + Pipe::connect(std::path::Path::new(sock_path)).unwrap() } /// There are some methods we need in order to run askpass correctly, @@ -18,7 +21,7 @@ pub trait UnixCompatibility: Sized { fn set_read_timeout(&self, timeout: Option) -> io::Result<()>; } -impl UnixCompatibility for PipeStream { +impl UnixCompatibility for Pipe { fn try_clone(&self) -> Option { Some(unsafe { Self::from_raw_handle(self.as_raw_handle()) }) } @@ -32,28 +35,14 @@ impl UnixCompatibility for PipeStream { // NOTE(qix-): // NOTE(qix-): This is indeed the case here, but we try to make it work // NOTE(qix-): anyway. - #[allow(unused_assignments)] - let mut timeout_ms: winapi::shared::minwindef::DWORD = 0; - let timeout_ptr: winapi::shared::minwindef::LPDWORD = if let Some(timeout) = timeout { - timeout_ms = timeout.as_millis() as winapi::shared::minwindef::DWORD; - &mut timeout_ms as *mut _ - } else { - std::ptr::null_mut() - }; + let timeout_ms: Option<*const u32> = + timeout.map(|timeout| timeout.as_millis() as *const u32); - let r = unsafe { - winapi::um::namedpipeapi::SetNamedPipeHandleState( - self.as_raw_handle() as winapi::um::winnt::HANDLE, - std::ptr::null_mut(), - std::ptr::null_mut(), - timeout_ptr, - ) - }; + let r = unsafe { SetNamedPipeHandleState(self.get_handle(), None, None, timeout_ms) }; - if r == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(()) + match r { + Ok(_) => Ok(()), + Err(err) => Err(io::Error::from_raw_os_error(err.code().0)), } } } diff --git a/crates/gitbutler-git/src/executor/tokio/windows.rs b/crates/gitbutler-git/src/executor/tokio/windows.rs index 60c63686b..8ad4d627b 100644 --- a/crates/gitbutler-git/src/executor/tokio/windows.rs +++ b/crates/gitbutler-git/src/executor/tokio/windows.rs @@ -10,30 +10,25 @@ use tokio::{ net::windows::named_pipe::{NamedPipeServer, ServerOptions}, sync::Mutex, }; +use windows::Win32::{Foundation::HANDLE, System::Pipes::GetNamedPipeClientProcessId}; -const ASKPASS_PIPE_PREFIX: &str = r"\\.\pipe\gitbutler-askpass-"; +// Slashes instead of backslashes to prevent any issues with escaping. +const ASKPASS_PIPE_PREFIX: &str = r"//./pipe/gitbutler-askpass-"; impl Socket for BufStream { type Error = std::io::Error; fn pid(&self) -> Result { let raw_handle = self.get_ref().as_raw_handle(); - let mut out_pid: winapi::shared::minwindef::ULONG = 0; + let handle: HANDLE = HANDLE(raw_handle as isize); + let mut out_pid: u32 = 0; #[allow(unsafe_code)] - let r = unsafe { - winapi::um::winbase::GetNamedPipeClientProcessId( - // We need the `as` here to make rustdoc shut up - // about winapi using different type defs for docs. - raw_handle as winapi::um::winnt::HANDLE, - &mut out_pid, - ) - }; + let r = unsafe { GetNamedPipeClientProcessId(handle, &mut out_pid) }; - if r == 0 { - Err(std::io::Error::last_os_error()) - } else { - Ok(Pid::from(out_pid)) + match r { + Err(err) => Err(std::io::Error::from_raw_os_error(err.code().0)), + Ok(_) => Ok(Pid::from(out_pid)), } } From 7b509c4dcd1eb999866e5cfbb8ed9fd37a889f78 Mon Sep 17 00:00:00 2001 From: Lukylix Date: Thu, 20 Jun 2024 16:43:25 +0200 Subject: [PATCH 2/7] Windows Pipe CloseHandle and Cloning --- crates/gitbutler-git/Cargo.toml | 1 + .../src/bin/askpass/windows-pipe.rs | 37 ++++++++++++++++++- .../gitbutler-git/src/bin/askpass/windows.rs | 11 +----- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/crates/gitbutler-git/Cargo.toml b/crates/gitbutler-git/Cargo.toml index 4e7649a58..0da463879 100644 --- a/crates/gitbutler-git/Cargo.toml +++ b/crates/gitbutler-git/Cargo.toml @@ -52,6 +52,7 @@ windows = { version = "0.57.0", features = [ "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_IO", + "Win32_System_Threading", ] } tokio = { workspace = true, optional = true, features = ["sync"] } diff --git a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs index a77b5e22c..6a4772f74 100644 --- a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs +++ b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs @@ -5,13 +5,15 @@ use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle} use std::path::Path; use windows::core::PWSTR; use windows::Win32::Foundation::{ - ERROR_PIPE_NOT_CONNECTED, GENERIC_READ, GENERIC_WRITE, HANDLE, WIN32_ERROR, + CloseHandle, DuplicateHandle, BOOL, DUPLICATE_SAME_ACCESS, ERROR_PIPE_NOT_CONNECTED, + GENERIC_READ, GENERIC_WRITE, HANDLE, WIN32_ERROR, }; use windows::Win32::Storage::FileSystem::{ CreateFileW, FlushFileBuffers, ReadFile, WriteFile, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, }; use windows::Win32::System::Pipes::{WaitNamedPipeW, NMPWAIT_USE_DEFAULT_WAIT}; +use windows::Win32::System::Threading::GetCurrentProcess; #[derive(Debug)] struct Handle { @@ -21,6 +23,34 @@ struct Handle { unsafe impl Send for Handle {} unsafe impl Sync for Handle {} +impl Handle { + fn try_clone(&self) -> io::Result { + let mut new_handle = HANDLE::default(); + let current_ps_handle: HANDLE = unsafe { GetCurrentProcess() }; + let res = unsafe { + DuplicateHandle( + current_ps_handle, + self.inner, + current_ps_handle, + &mut new_handle as *mut HANDLE, + 0, + BOOL(1), + DUPLICATE_SAME_ACCESS, + ) + }; + match res { + Ok(_) => Ok(Handle { inner: new_handle }), + Err(err) => Err(io::Error::from_raw_os_error(err.code().0)), + } + } +} + +impl Drop for Handle { + fn drop(&mut self) { + let _ = unsafe { CloseHandle(self.inner) }; + } +} + #[derive(Debug)] pub struct Pipe { handle: Handle, @@ -57,6 +87,11 @@ impl Pipe { pub fn get_handle(&self) -> HANDLE { self.handle.inner } + + pub fn try_clone(&self) -> io::Result { + let handle = self.handle.try_clone()?; + Ok(Pipe { handle }) + } } impl Drop for Pipe { diff --git a/crates/gitbutler-git/src/bin/askpass/windows.rs b/crates/gitbutler-git/src/bin/askpass/windows.rs index 916a20bd3..14afb704a 100644 --- a/crates/gitbutler-git/src/bin/askpass/windows.rs +++ b/crates/gitbutler-git/src/bin/askpass/windows.rs @@ -1,8 +1,4 @@ -use std::{ - io, - os::windows::io::{AsRawHandle, FromRawHandle}, - time::Duration, -}; +use std::{io, time::Duration}; use windows::Win32::System::Pipes::SetNamedPipeHandleState; #[path = "windows-pipe.rs"] mod windows_pipe; @@ -17,15 +13,10 @@ pub fn establish(sock_path: &str) -> Pipe { /// We stub them using this trait so we don't have to newtype /// the pipestream itself (which would be extensive and un-DRY). pub trait UnixCompatibility: Sized { - fn try_clone(&self) -> Option; fn set_read_timeout(&self, timeout: Option) -> io::Result<()>; } impl UnixCompatibility for Pipe { - fn try_clone(&self) -> Option { - Some(unsafe { Self::from_raw_handle(self.as_raw_handle()) }) - } - fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { // NOTE(qix-): Technically, this shouldn't work (and probably doesn't). // NOTE(qix-): The documentation states: From 1d940c8204d8dd61e6a0c6bc7aab73a612bd76fc Mon Sep 17 00:00:00 2001 From: Lukylix Date: Thu, 20 Jun 2024 16:43:51 +0200 Subject: [PATCH 3/7] Cargo.lock --- Cargo.lock | 181 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73cea1430..b50f89118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -810,7 +810,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1307,7 +1307,7 @@ checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1330,7 +1330,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1484,7 +1484,7 @@ checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1745,7 +1745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2071,7 +2071,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps 6.2.0", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2173,8 +2173,7 @@ dependencies = [ "thiserror", "tokio", "uuid", - "winapi 0.3.9", - "windows-named-pipe", + "windows 0.57.0", ] [[package]] @@ -3404,7 +3403,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -3699,16 +3698,6 @@ dependencies = [ "treediff", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "kqueue" version = "1.0.8" @@ -4145,7 +4134,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4155,7 +4144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4524,7 +4513,7 @@ dependencies = [ "libc", "redox_syscall 0.2.16", "smallvec", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -5888,7 +5877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -6253,7 +6242,7 @@ dependencies = [ "unicode-segmentation", "uuid", "windows 0.39.0", - "windows-implement", + "windows-implement 0.39.0", "x11-dl", ] @@ -6421,7 +6410,7 @@ dependencies = [ "serde", "tauri", "time", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -6994,7 +6983,7 @@ checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ "memoffset 0.9.1", "tempfile", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7315,7 +7304,7 @@ dependencies = [ "webview2-com-macros", "webview2-com-sys", "windows 0.39.0", - "windows-implement", + "windows-implement 0.39.0", ] [[package]] @@ -7350,12 +7339,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -7366,12 +7349,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -7384,7 +7361,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7412,7 +7389,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" dependencies = [ - "windows-implement", + "windows-implement 0.39.0", "windows_aarch64_msvc 0.39.0", "windows_i686_gnu 0.39.0", "windows_i686_msvc 0.39.0", @@ -7435,8 +7412,18 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", - "windows-targets 0.52.4", + "windows-core 0.52.0", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.5", ] [[package]] @@ -7455,7 +7442,19 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement 0.57.0", + "windows-interface", + "windows-result", + "windows-targets 0.52.5", ] [[package]] @@ -7468,6 +7467,28 @@ dependencies = [ "windows-tokens", ] +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "windows-metadata" version = "0.39.0" @@ -7475,13 +7496,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" [[package]] -name = "windows-named-pipe" -version = "0.1.0" +name = "windows-result" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808ba65b3d86cc5465971ad08ee3850e197cc8d5719277611fabb27827c02388" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ - "kernel32-sys", - "winapi 0.2.8", + "windows-targets 0.52.5", ] [[package]] @@ -7523,7 +7543,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -7558,17 +7578,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -7583,7 +7604,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -7600,9 +7621,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -7630,9 +7651,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -7660,9 +7681,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -7690,9 +7717,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -7720,9 +7747,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -7738,9 +7765,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -7768,9 +7795,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -7845,7 +7872,7 @@ dependencies = [ "webkit2gtk-sys", "webview2-com", "windows 0.39.0", - "windows-implement", + "windows-implement 0.39.0", ] [[package]] @@ -7896,7 +7923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7939,7 +7966,7 @@ dependencies = [ "static_assertions", "tracing", "uds_windows", - "winapi 0.3.9", + "winapi", "xdg-home", "zbus_macros", "zbus_names", From 2d7b7737bea5ec282c18ba81c2b8a727b4066b3f Mon Sep 17 00:00:00 2001 From: Lukylix Date: Fri, 21 Jun 2024 22:49:19 +0200 Subject: [PATCH 4/7] Askpass test --- Cargo.lock | 70 +++++++++++++++++++ crates/gitbutler-git/Cargo.toml | 4 ++ .../gitbutler-git/src/executor/tokio/mod.rs | 48 +++++++++++++ 3 files changed, 122 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index b50f89118..06932a083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,6 +163,21 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "assert_cmd" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + [[package]] name = "async-broadcast" version = "0.5.1" @@ -1250,6 +1265,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "diffy" version = "0.3.0" @@ -1339,6 +1360,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "dtoa" version = "1.0.9" @@ -2165,6 +2192,7 @@ dependencies = [ name = "gitbutler-git" version = "0.0.0" dependencies = [ + "assert_cmd", "futures", "nix 0.29.0", "rand 0.8.5", @@ -4859,6 +4887,33 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "difflib", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -6572,6 +6627,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "thin-slice" version = "0.1.1" @@ -7122,6 +7183,15 @@ dependencies = [ "libc", ] +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.1.1" diff --git a/crates/gitbutler-git/Cargo.toml b/crates/gitbutler-git/Cargo.toml index 0da463879..058d026ae 100644 --- a/crates/gitbutler-git/Cargo.toml +++ b/crates/gitbutler-git/Cargo.toml @@ -56,6 +56,10 @@ windows = { version = "0.57.0", features = [ ] } tokio = { workspace = true, optional = true, features = ["sync"] } +[dev-dependencies] +assert_cmd = "2.0.14" +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + [lints.clippy] all = "deny" perf = "deny" diff --git a/crates/gitbutler-git/src/executor/tokio/mod.rs b/crates/gitbutler-git/src/executor/tokio/mod.rs index 980034f1b..e338bc562 100644 --- a/crates/gitbutler-git/src/executor/tokio/mod.rs +++ b/crates/gitbutler-git/src/executor/tokio/mod.rs @@ -138,3 +138,51 @@ unsafe impl super::GitExecutor for TokioExecutor { } } } +#[cfg(test)] +mod tests { + use super::*; + + use crate::executor::AskpassServer; + use crate::executor::GitExecutor; + use crate::executor::Socket; + use assert_cmd::Command; + use std::time::Duration; + + // cargo test --package gitbutler-git --lib test_askpass + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_askpass() { + let secret = "super-secret-secret"; + let executor = TokioExecutor; + #[allow(unsafe_code)] + let sock_server: TokioAskpassServer = unsafe { executor.create_askpass_server() } + .await + .expect("create_askpass_server():"); + let sock_server_string = sock_server.to_string(); + let handle = tokio::spawn(async move { + let mut cmd = Command::cargo_bin("gitbutler-git-askpass").unwrap(); + let assert = cmd + .env("GITBUTLER_ASKPASS_PIPE", sock_server_string) + .env("GITBUTLER_ASKPASS_SECRET", secret) + .arg("Please enter your password:") + .assert(); + assert.success().stdout("super_secret_password\n"); + }); + + let mut sock = sock_server + .accept(Some(Duration::from_secs(10))) + .await + .expect("accept():"); + + let peer_secret = sock.read_line().await.expect("read_line() peer_secret:"); + + assert_eq!(peer_secret, secret); + + let prompt = sock.read_line().await.expect("read_line() prompt:"); + assert_eq!(prompt.trim(), "Please enter your password:"); + + sock.write_line("super_secret_password") + .await + .expect("write_line() password:"); + handle.await.expect("Askpass command failed"); + } +} From e42026188d7fa9b40f9bb9e9c19ad6fabd28492d Mon Sep 17 00:00:00 2001 From: Lukylix Date: Fri, 21 Jun 2024 22:50:02 +0200 Subject: [PATCH 5/7] Limiting pipe instances on windows --- crates/gitbutler-git/src/executor/tokio/windows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/gitbutler-git/src/executor/tokio/windows.rs b/crates/gitbutler-git/src/executor/tokio/windows.rs index 8ad4d627b..27b74d7bd 100644 --- a/crates/gitbutler-git/src/executor/tokio/windows.rs +++ b/crates/gitbutler-git/src/executor/tokio/windows.rs @@ -59,6 +59,7 @@ impl TokioAskpassServer { let server = Mutex::new(RefCell::new( ServerOptions::new() .first_pipe_instance(true) + .max_instances(2) .create(&connection_string)?, )); From 5bc830baa0baba0bdcb6995e44bd3122619f7f8e Mon Sep 17 00:00:00 2001 From: Lukylix Date: Fri, 21 Jun 2024 22:55:48 +0200 Subject: [PATCH 6/7] Wide path convertion --- crates/gitbutler-git/src/bin/askpass/windows-pipe.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs index 6a4772f74..6a11a537e 100644 --- a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs +++ b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs @@ -58,9 +58,11 @@ pub struct Pipe { impl Pipe { pub fn connect(path: &Path) -> io::Result { - let mut os_str: OsString = path.as_os_str().into(); - os_str.push("\x00"); - let mut wide_path: Vec = os_str.encode_wide().collect(); + let mut wide_path: Vec = path + .as_os_str() + .encode_wide() + .chain(std::iter::once(0)) + .collect(); let pwstr_path = PWSTR(wide_path.as_mut_ptr()); let _ = unsafe { WaitNamedPipeW(pwstr_path, NMPWAIT_USE_DEFAULT_WAIT) }; From 3a079593b299cc5c965f8e55e39e564ca160d6ab Mon Sep 17 00:00:00 2001 From: Lukylix Date: Fri, 21 Jun 2024 23:28:08 +0200 Subject: [PATCH 7/7] Removed an unused import --- crates/gitbutler-git/src/bin/askpass/windows-pipe.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs index 6a11a537e..6268b5153 100644 --- a/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs +++ b/crates/gitbutler-git/src/bin/askpass/windows-pipe.rs @@ -1,4 +1,3 @@ -use std::ffi::OsString; use std::io::{self, Read, Write}; use std::os::windows::ffi::OsStrExt; use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};