From 4732867ffa8041a3406dade3ae3ad32cf95f0a0c Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 28 Feb 2026 19:19:28 +0100 Subject: add authentication barebone --- src/bin/client/repl.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 2 deletions(-) (limited to 'src/bin/client/repl.rs') diff --git a/src/bin/client/repl.rs b/src/bin/client/repl.rs index 1512091..5559cfd 100644 --- a/src/bin/client/repl.rs +++ b/src/bin/client/repl.rs @@ -2,10 +2,18 @@ use std::io::{BufRead, BufReader, Write, stdout}; use std::net::TcpStream; use rusqlite::Connection; use std::time::Instant; +use bcrypt::hash_with_salt; use crate::connection; use crate::database; +const SALT: [u8; 16] = *b"fixedsalt1234567"; + +fn hash_password(password: &str) -> String { + let result = hash_with_salt(password, 10, SALT).unwrap(); + result.to_string() +} + use crossterm::{event::{read, Event, KeyCode, KeyModifiers}, terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType}, cursor::{MoveToColumn, Show}, execute}; macro_rules! println { @@ -47,7 +55,7 @@ impl ClientState { pub fn connect_to(&mut self, addr: &str) { self.addr = Some(addr.to_string()); - match connection::connect(addr) { + match connection::connect(addr, &self.conn) { Ok(s) => { self.stream = Some(s); database::save_host(&self.conn, addr); @@ -166,6 +174,108 @@ impl ClientState { } } } + "register" => { + if self.stream.is_none() { + println!("\nNot connected. Use 'connect :' first."); + continue 'outer; + } + let username = read_line("\nUsername: "); + if username.is_empty() { + continue 'outer; + } + let password = read_line("Password: "); + if password.is_empty() { + continue 'outer; + } + let hashed = hash_password(&password); + let msg = format!("REGISTER {} {}", username, hashed); + let s = self.stream.as_mut().unwrap(); + let writer_stream = s.try_clone().unwrap(); + let mut writer = writer_stream; + let response_reader_stream = s.try_clone().unwrap(); + let mut response_reader = BufReader::new(response_reader_stream); + if let Err(_) = writeln!(writer, "{}", msg) { + self.stream = None; + println!("\nConnection lost"); + continue 'outer; + } + let mut response = String::new(); + if let Err(_) = response_reader.read_line(&mut response) { + self.stream = None; + println!("\nConnection lost"); + } else { + println!("\n{}", response.trim()); + } + } + "login" => { + if self.stream.is_none() { + println!("\nNot connected. Use 'connect :' first."); + continue 'outer; + } + loop { + let username = read_line("\nUsername: "); + if username.is_empty() { + break; + } + let password = read_line("Password: "); + if password.is_empty() { + break; + } + let hashed = hash_password(&password); + let msg = format!("AUTH {} {}", username, hashed); + let s = self.stream.as_mut().unwrap(); + let writer_stream = s.try_clone().unwrap(); + let mut writer = writer_stream; + let response_reader_stream = s.try_clone().unwrap(); + let mut response_reader = BufReader::new(response_reader_stream); + if let Err(_) = writeln!(writer, "{}", msg) { + self.stream = None; + println!("\nConnection lost"); + break; + } + let mut response = String::new(); + if let Err(_) = response_reader.read_line(&mut response) { + self.stream = None; + println!("\nConnection lost"); + break; + } else { + let resp = response.trim(); + println!("\n{}", resp); + if resp.starts_with("OK") { + // Save credentials + if let Some(addr) = &self.addr { + if let Err(e) = database::save_credentials(&self.conn, addr, &username, &password) { + println!("Failed to save credentials: {}", e); + } + } + break; + } else { + println!("Authentication failed, try again or press Enter to cancel."); + } + } + } + } + "setcred" => { + if self.addr.is_none() { + println!("\nNo host connected. Use 'connect :' first."); + continue 'outer; + } + let username = read_line("\nUsername: "); + if username.is_empty() { + continue 'outer; + } + let password = read_line("Password: "); + if password.is_empty() { + continue 'outer; + } + if let Some(addr) = &self.addr { + if let Err(e) = database::save_credentials(&self.conn, addr, &username, &password) { + println!("Failed to save credentials: {}", e); + } else { + println!("Credentials saved for {}", addr); + } + } + } "help" => { help(); } @@ -208,6 +318,18 @@ fn redraw(current_input: &str) { execute!(stdout(), MoveToColumn((2 + current_input.len()) as u16)).unwrap(); } +fn read_line(prompt: &str) -> String { + disable_raw_mode().unwrap(); + execute!(stdout(), Show).unwrap(); + print!("{}", prompt); + stdout().flush().unwrap(); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + enable_raw_mode().unwrap(); + execute!(stdout(), crossterm::cursor::Hide).unwrap(); + input.trim().to_string() +} + fn help() { - println!("Available commands: connect :, send , disconnect, ping, help, quit"); + println!("Available commands: connect :, send , disconnect, ping, login, register, setcred, help, quit"); } -- cgit v1.2.3