From 95cf972f5b2d5d06ad8d6c7de2489330f1764347 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sat, 12 Aug 2017 12:32:25 +0300 Subject: [PATCH] First version of the proxy --- Cargo.toml | 10 ++++++ README.md | 5 +++ src/main.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cecbc13 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "keepassxc-proxy" +version = "0.1.0" +authors = ["varjolintu "] +keywords = ["native", "messaging", "host", "protocol", "keepassxc"] +license = "GPL-3.0" +repository = "https://github.com/varjolintu/keepassxc-proxy-rust" + +[dependencies] +byteorder = "1.1.0" \ No newline at end of file diff --git a/README.md b/README.md index bd73bef..2d8b9d2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # keepassxc-proxy-rust Application that works as a proxy between Native Messaging browser extension and KeePassXC + +This is still under development. Installing the proxy needs manual changes to JSON scripts installed for Native Messaging. +See [this page](https://developer.chrome.com/extensions/nativeMessaging) for further information. + +keepassxc-proxy listens stdin from keepassxc-browser extension and transfers the data to UDP port 19700 which KeePassXC listens. \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6bbc743 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,94 @@ +extern crate byteorder; + +use std::io::{self, Read, Write}; +use std::net::UdpSocket; +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 +} + +fn read_header() -> (u32) +{ + let stdin = io::stdin(); + let mut buf = vec![0; 4]; + let mut handle = stdin.lock(); + + handle.read_exact(&mut buf); + let length: u32 = NativeEndian::read_u32(&buf); + return length; +} + +fn read_body(length: u32, socket: &UdpSocket) +{ + 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.send_to(&buffer, "127.0.0.1:19700").expect("Cannot send data"); + } + }, + Err(e) => panic!("Read error: {}", e) + } +} + +fn read_udp_response(socket: &UdpSocket) +{ + let mut buf = [0; 4069]; + + match socket.recv_from(&mut buf) { + Ok((length, src)) => { + if valid_length(length as u32) { + thread::spawn(move || { + let text = str::from_utf8(&buf).unwrap(); + write_output(text); + }); + } + }, + Err(e) => panic!("Read error: {}", e) + } +} + +fn write_output(text: &str) +{ + let textlen = text.len(); + let stdout = io::stdout(); + let mut handle = stdout.lock(); + + handle.write_u32::(textlen as u32).unwrap(); + handle.write(text.as_bytes()); +} + +fn main() { + + let socket = UdpSocket::bind("127.0.0.1:0").expect("Couldn't bind to address"); + let timeout: Option = Some(Duration::from_secs(1)); + socket.set_read_timeout(timeout); + + // 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); + } + }); + + // Start thread for UDP packet receiving + let recv_socket = socket.try_clone().expect("Cannot clone socket"); + let pr = thread::spawn(move || { + loop { + read_udp_response(&recv_socket); + } + }); + + let ui_res = ui.join(); + let pr_res = pr.join(); +} \ No newline at end of file