diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6f89c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ceeca24 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,47 @@ +[[package]] +name = "byteorder" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "keepassxc-proxy" +version = "0.1.0" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "named_pipe 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "named_pipe" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum named_pipe 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "516fe2b5b1131f912a3d4e0cbfec369ca9a65f89d477c15d86ef0fc376faaa55" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index cecbc13..635468a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,7 @@ license = "GPL-3.0" repository = "https://github.com/varjolintu/keepassxc-proxy-rust" [dependencies] -byteorder = "1.1.0" \ No newline at end of file +byteorder = "1.1.0" + +[target.'cfg(windows)'.dependencies] +named_pipe = "0.2" diff --git a/src/main.rs b/src/main.rs index 53002f1..ad6578c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,83 +1,70 @@ extern crate byteorder; +#[cfg(windows)] +extern crate named_pipe; use std::io::{self, Read, Write}; -use std::os::unix::net::UnixStream; -use std::os::unix::net::UnixListener; -use std::str; use std::thread; -use std::time::Duration; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; -fn valid_length(length: u32) -> bool -{ - return length > 0 && length <= 4096; // 1024 ^ 2 is the maximum +mod proxy_socket; + +use proxy_socket::ProxySocket; + +const BUFFER_SIZE: u32 = 1024 * 16; + +fn valid_length(length: u32) -> bool { + return length > 0 && length <= 4096; // 1024 ^ 2 is the maximum } -fn read_header() -> (u32) -{ +fn read_header() -> u32 { let stdin = io::stdin(); let mut buf = vec![0; 4]; let mut handle = stdin.lock(); handle.read_exact(&mut buf).unwrap(); - let length: u32 = NativeEndian::read_u32(&buf); - return length; + NativeEndian::read_u32(&buf) } -fn read_body(length: u32, mut socket: &UnixStream) -{ +fn read_body(length: u32, socket: &mut ProxySocket) { let mut buffer = vec![0; length as usize]; let stdin = io::stdin(); let mut handle = stdin.lock(); - match handle.read_exact(&mut buffer) { - Ok(_v) => { - if valid_length(length) { - socket.write(&buffer).unwrap(); - socket.flush().unwrap(); - read_unix_response(length, &socket); - } - }, - Err(_e) => {} + if let Ok(_) = handle.read_exact(&mut buffer) { + if valid_length(length) { + socket.write(&buffer).unwrap(); + socket.flush().unwrap(); + read_response(socket); + } } } -fn read_unix_response(length: u32, mut socket: &UnixStream) -{ - let mut buf = vec![0; length as usize]; - - match socket.read(&mut buf) { - Ok(_length) => { - let text = str::from_utf8(&buf).unwrap(); - write_output(text); - }, - Err(_e) => {} - } +fn read_response(socket: &mut ProxySocket) { + let mut buf = vec![0; BUFFER_SIZE as usize]; + if let Ok(len) = socket.read(&mut buf) { + write_response(&buf[0..len]); + } } -fn write_output(text: &str) -{ - let textlen = text.len(); +fn write_response(buf: &[u8]) { let stdout = io::stdout(); - let mut handle = stdout.lock(); + let mut out = stdout.lock(); - handle.write_u32::(textlen as u32).unwrap(); - handle.write(text.as_bytes()).unwrap(); + out.write_u32::(buf.len() as u32).unwrap(); + out.write(buf).unwrap(); + out.flush().unwrap(); } fn main() { - let socket = UnixStream::connect("/tmp/kpxc_server").unwrap(); - let timeout: Option = Some(Duration::from_secs(1)); - socket.set_read_timeout(timeout).unwrap(); + let mut socket = proxy_socket::connect().unwrap(); // Start thread for user input reading - let send_socket = socket.try_clone().expect("Cannot clone socket"); let ui = thread::spawn(move || { loop { let length = read_header(); - read_body(length, &send_socket); - } - }); + read_body(length, &mut socket); + } + }); - let _ui_res = ui.join(); + let _ui_res = ui.join().unwrap(); } diff --git a/src/proxy_socket.rs b/src/proxy_socket.rs new file mode 100644 index 0000000..50c2ed4 --- /dev/null +++ b/src/proxy_socket.rs @@ -0,0 +1,53 @@ +use std::env; +use std::io::{self, Read, Write}; + +#[cfg(not(windows))] +use std::os::unix::net::UnixStream; + +#[cfg(windows)] +use named_pipe::PipeClient; + +pub struct ProxySocket { + inner: T, +} + +impl Read for ProxySocket { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +impl Write for ProxySocket { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(windows)] +pub fn connect() -> io::Result> { + let temp_path = env::var("TEMP").unwrap(); + let pipe_name = format!("\\\\.\\pipe\\{}\\kpxc_server", temp_path); + let client = PipeClient::connect(pipe_name)?; + Ok(ProxySocket { inner: client }) +} + +#[cfg(not(windows))] +pub fn connect() -> io::Result> { + use std::time::Duration; + + let socket_name = "kpxc_server"; + let socket: String; + if let Ok(xdg) = env::var("XDG_RUNTIME_DIR") { + socket = format!("{}/{}", xdg, socket_name); + } else { + socket = format!("/tmp/{}", socket_name); + } + let s = UnixStream::connect(socket)?; + let timeout: Option = Some(Duration::from_secs(1)); + s.set_read_timeout(timeout)?; + Ok(ProxySocket { inner: s }) +}