diff --git a/src/frontend/index.js b/src/frontend/index.js index 351f54a..b3a4532 100644 --- a/src/frontend/index.js +++ b/src/frontend/index.js @@ -335,32 +335,35 @@ profileDiv.onclick = function() { changePasswordButton.textContent = "Change password"; changePasswordButton.onclick = function() { let inputs = document.querySelectorAll("input[type=\"password\"]"); - let newPassword, newPasswordConfirm; + let newPassword, newPasswordConfirm, oldPassword; if (isIdentityProtected) { - newPassword = inputs[1]; - newPasswordConfirm = inputs[2]; + oldPassword = inputs[0].value; + newPassword = inputs[1].value; + newPasswordConfirm = inputs[2].value; } else { - newPassword = inputs[0]; - newPasswordConfirm = inputs[1]; + newPassword = inputs[0].value; + newPasswordConfirm = inputs[1].value; } - if (newPassword.value == newPasswordConfirm.value) { - let newPassword_set = newPassword.value.length > 0; - if (isIdentityProtected || newPassword_set) { //don't change password if identity is not protected and new password is blank + if (newPassword == newPasswordConfirm) { + let newPasswordSet = newPassword.length > 0; + if (isIdentityProtected && oldPassword.length == 0) { + errorMsg.textContent = "Current password cannot be empty."; + } else if (isIdentityProtected || newPasswordSet) { //don't change password if identity is not protected and new password is blank let msg = "change_password"; if (isIdentityProtected) { msg += " "+b64EncodeUnicode(inputs[0].value); } - if (newPassword_set) { - msg += " "+b64EncodeUnicode(newPassword.value); + if (newPasswordSet) { + msg += " "+b64EncodeUnicode(newPassword); } socket.send(msg); } else { removePopup(); } } else { - newPassword.value = ""; - newPasswordConfirm.value = ""; - errorMsg.textContent = "Passwords don't match"; + newPassword = ""; + newPasswordConfirm = ""; + errorMsg.textContent = "Passwords don't match."; } }; sectionPassword.appendChild(changePasswordButton); diff --git a/src/identity.rs b/src/identity.rs index 08ae660..fb8fdf3 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -94,8 +94,8 @@ impl Identity { }; Ok(Contact { uuid: contact_uuid, - public_key: public_key, - name: name, + public_key, + name, avatar: avatar_uuid, verified: false, seen: true, @@ -277,27 +277,23 @@ impl Identity { let encrypted_outgoing: Vec = row.get(0).unwrap(); match crypto::decrypt_data(encrypted_outgoing.as_slice(), &self.master_key){ Ok(outgoing) => { - match byte_to_bool(outgoing[0]) { - Ok(outgoing) => { - let encrypted_timestamp: Vec = row.get(1).unwrap(); - match crypto::decrypt_data(&encrypted_timestamp, &self.master_key) { - Ok(timestamp) => { - let encrypted_data: Vec = row.get(2).unwrap(); - match crypto::decrypt_data(encrypted_data.as_slice(), &self.master_key) { - Ok(data) => msgs.push(Message { - outgoing, - timestamp: u64::from_be_bytes(timestamp.try_into().unwrap()), - data, - }), - Err(e) => print_error!(e) - } + if let Ok(outgoing) = byte_to_bool(outgoing[0]) { + let encrypted_timestamp: Vec = row.get(1).unwrap(); + match crypto::decrypt_data(&encrypted_timestamp, &self.master_key) { + Ok(timestamp) => { + let encrypted_data: Vec = row.get(2).unwrap(); + match crypto::decrypt_data(encrypted_data.as_slice(), &self.master_key) { + Ok(data) => msgs.push(Message { + outgoing, + timestamp: u64::from_be_bytes(timestamp.try_into().unwrap()), + data, + }), + Err(e) => print_error!(e) } - Err(e) => print_error!(e) } + Err(e) => print_error!(e) } - Err(_) => {} } - } Err(e) => print_error!(e) } @@ -382,14 +378,8 @@ impl Identity { pub fn load_identity(password: Option<&[u8]>) -> Result { match Identity::load_encrypted_identity() { Ok(encrypted_identity) => { - let master_key: [u8; crypto::MASTER_KEY_LEN] = if password.is_none() { - if encrypted_identity.encrypted_master_key.len() == crypto::MASTER_KEY_LEN { - encrypted_identity.encrypted_master_key.try_into().unwrap() - } else { - return Err(String::from(DATABASE_CORRUPED_ERROR)) - } - } else { - match crypto::decrypt_master_key(&encrypted_identity.encrypted_master_key, password.unwrap(), &encrypted_identity.salt) { + let master_key: [u8; crypto::MASTER_KEY_LEN] = match password { + Some(password) => match crypto::decrypt_master_key(&encrypted_identity.encrypted_master_key, password, &encrypted_identity.salt) { Ok(master_key) => master_key, Err(e) => return Err( match e { @@ -398,6 +388,11 @@ impl Identity { } ) } + None => if encrypted_identity.encrypted_master_key.len() == crypto::MASTER_KEY_LEN { + encrypted_identity.encrypted_master_key.try_into().unwrap() + } else { + return Err(String::from(DATABASE_CORRUPED_ERROR)) + } }; match crypto::decrypt_data(&encrypted_identity.encrypted_keypair, &master_key) { Ok(keypair) => { @@ -443,13 +438,16 @@ impl Identity { let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?; db.set(DBKeys::NAME, name.as_bytes())?; db.set(DBKeys::KEYPAIR, &encrypted_keypair)?; - let salt = if password.is_none() { //no password - db.set(DBKeys::MASTER_KEY, &master_key)?; //storing master_key in plaintext - [0; crypto::SALT_LEN] - } else { - let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, password.unwrap()); - db.set(DBKeys::MASTER_KEY, &encrypted_master_key)?; - salt + let salt = match password { + Some(password) => { + let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, password); + db.set(DBKeys::MASTER_KEY, &encrypted_master_key)?; + salt + } + None => { + db.set(DBKeys::MASTER_KEY, &master_key)?; //storing master_key in plaintext + [0; crypto::SALT_LEN] + } }; db.set(DBKeys::SALT, &salt)?; let encrypted_use_padding = crypto::encrypt_data(&[bool_to_byte(true)], &master_key).unwrap(); @@ -464,13 +462,16 @@ impl Identity { fn update_master_key(master_key: [u8; crypto::MASTER_KEY_LEN], new_password: Option<&[u8]>) -> Result { let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?; - let salt = if new_password.is_none() { //no password - db.update(DBKeys::MASTER_KEY, &master_key)?; - [0; crypto::SALT_LEN] - } else { - let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, new_password.unwrap()); - db.update(DBKeys::MASTER_KEY, &encrypted_master_key)?; - salt + let salt = match new_password { + Some(new_password) => { + let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, new_password); + db.update(DBKeys::MASTER_KEY, &encrypted_master_key)?; + salt + } + None => { + db.update(DBKeys::MASTER_KEY, &master_key)?; + [0; crypto::SALT_LEN] + } }; db.update(DBKeys::SALT, &salt) } @@ -478,20 +479,19 @@ impl Identity { pub fn change_password(old_password: Option<&[u8]>, new_password: Option<&[u8]>) -> Result { match Identity::load_encrypted_identity() { Ok(encrypted_identity) => { - let master_key: [u8; crypto::MASTER_KEY_LEN] = if old_password.is_none() { - if encrypted_identity.encrypted_master_key.len() == crypto::MASTER_KEY_LEN { - encrypted_identity.encrypted_master_key.try_into().unwrap() - } else { - return Err(String::from(DATABASE_CORRUPED_ERROR)) - } - } else { - match crypto::decrypt_master_key(&encrypted_identity.encrypted_master_key, old_password.unwrap(), &encrypted_identity.salt) { + let master_key: [u8; crypto::MASTER_KEY_LEN] = match old_password { + Some(old_password) => match crypto::decrypt_master_key(&encrypted_identity.encrypted_master_key, old_password, &encrypted_identity.salt) { Ok(master_key) => master_key, Err(e) => return match e { CryptoError::DecryptionFailed => Ok(false), CryptoError::InvalidLength => Err(String::from(DATABASE_CORRUPED_ERROR)) } } + None => if encrypted_identity.encrypted_master_key.len() == crypto::MASTER_KEY_LEN { + encrypted_identity.encrypted_master_key.try_into().unwrap() + } else { + return Err(String::from(DATABASE_CORRUPED_ERROR)) + } }; match Identity::update_master_key(master_key, new_password) { Ok(_) => Ok(true), diff --git a/src/key_value_table.rs b/src/key_value_table.rs index e478233..91e4408 100644 --- a/src/key_value_table.rs +++ b/src/key_value_table.rs @@ -12,7 +12,7 @@ impl<'a> KeyValueTable<'a> { Ok(KeyValueTable {db, table_name}) } pub fn set(&self, key: &str, value: &[u8]) -> Result { - Ok(self.db.execute(&format!("INSERT INTO {} (key, value) VALUES (?1, ?2)", self.table_name), params![key, value])?) + self.db.execute(&format!("INSERT INTO {} (key, value) VALUES (?1, ?2)", self.table_name), params![key, value]) } pub fn get(&self, key: &str) -> Result, Error> { let mut stmt = self.db.prepare(&format!("SELECT value FROM {} WHERE key=\"{}\"", self.table_name, key))?; diff --git a/src/main.rs b/src/main.rs index 7bc8a25..e082f94 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ mod ui_interface; mod constants; mod discovery; -use std::{env, fs, io, net::SocketAddr, str::{FromStr, from_utf8}, sync::{Arc, RwLock}}; +use std::{env, fs, io, net::SocketAddr, str::{FromStr, from_utf8}, sync::{Arc, RwLock}, cmp::Ordering}; use image::GenericImageView; use tokio::{net::TcpListener, runtime::Handle, sync::mpsc}; use actix_web::{App, HttpMessage, HttpRequest, HttpResponse, HttpServer, http::{header, CookieBuilder}, web, web::Data}; @@ -25,8 +25,8 @@ use session_manager::{SessionManager, SessionCommand}; use ui_interface::UiConnection; async fn start_websocket_server(global_vars: Arc>) -> u16 { - let websocket_bind_addr = env::var("AIRA_WEBSOCKET_ADDR").unwrap_or("127.0.0.1".to_owned()); - let websocket_port = env::var("AIRA_WEBSOCKET_PORT").unwrap_or("0".to_owned()); + let websocket_bind_addr = env::var("AIRA_WEBSOCKET_ADDR").unwrap_or_else(|_| "127.0.0.1".to_owned()); + let websocket_port = env::var("AIRA_WEBSOCKET_PORT").unwrap_or_else(|_| "0".to_owned()); let server = TcpListener::bind(websocket_bind_addr+":"+&websocket_port).await.unwrap(); let websocket_port = server.local_addr().unwrap().port(); tokio::spawn(async move { @@ -114,7 +114,7 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc 0 { + if !msgs.1.is_empty() { ui_connection.load_msgs(&msgs.0, &msgs.1); } }); @@ -157,7 +157,7 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc = msg.split(" ").collect(); + let args: Vec<&str> = msg.split_whitespace().collect(); match args[0] { "set_seen" => { let session_id: usize = args[1].parse().unwrap(); @@ -177,9 +177,11 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc { @@ -274,11 +276,11 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc HttpResp match image::load_from_memory_with_format(&buffer, format) { Ok(image) => { let (width, height) = image.dimensions(); - let image = if width < height { - image.crop_imm(0, (height-width)/2, width, width) - } else if width > height { - image.crop_imm((width-height)/2, 0, height, height) - } else { - image + let image = match width.cmp(&height) { + Ordering::Greater => image.crop_imm((width-height)/2, 0, height, height), + Ordering::Less => image.crop_imm(0, (height-width)/2, width, width), + Ordering::Equal => image, }; let mut avatar = Vec::new(); image.write_to(&mut avatar, format).unwrap(); @@ -385,7 +385,7 @@ fn reply_with_avatar(avatar: Option>, name: Option<&str>) -> HttpRespons let svg = include_str!(concat!(env!("OUT_DIR"), "/text_avatar.svg")); #[cfg(debug_assertions)] let svg = replace_fields("src/frontend/imgs/text_avatar.svg"); - HttpResponse::Ok().content_type("image/svg+xml").body(svg.replace("LETTER", &name.chars().nth(0).unwrap_or('?').to_string())) + HttpResponse::Ok().content_type("image/svg+xml").body(svg.replace("LETTER", &name.chars().next().unwrap_or('?').to_string())) } None => HttpResponse::InternalServerError().finish() } @@ -393,7 +393,7 @@ fn reply_with_avatar(avatar: Option>, name: Option<&str>) -> HttpRespons } fn handle_avatar(req: HttpRequest) -> HttpResponse { - let splits: Vec<&str> = req.path()[1..].split("/").collect(); + let splits: Vec<&str> = req.path()[1..].split('/').collect(); if splits.len() == 2 { if splits[1] == "self" { return reply_with_avatar(Identity::get_identity_avatar().ok(), Identity::get_identity_name().ok().as_deref()); @@ -417,11 +417,8 @@ fn handle_load_file(req: HttpRequest, file_info: web::Query) -> HttpRe match Uuid::from_str(&file_info.uuid) { Ok(uuid) => { let global_vars = req.app_data::>>>().unwrap(); - match global_vars.read().unwrap().session_manager.identity.read().unwrap().as_ref().unwrap().load_file(uuid) { - Some(buffer) => { - return HttpResponse::Ok().header("Content-Disposition", format!("attachment; filename=\"{}\"", escape_double_quote(html_escape::decode_html_entities(&file_info.file_name).to_string()))).content_type("application/octet-stream").body(buffer); - } - None => {} + if let Some(buffer) = global_vars.read().unwrap().session_manager.identity.read().unwrap().as_ref().unwrap().load_file(uuid) { + return HttpResponse::Ok().header("Content-Disposition", format!("attachment; filename=\"{}\"", escape_double_quote(html_escape::decode_html_entities(&file_info.file_name).to_string()))).content_type("application/octet-stream").body(buffer); } } Err(e) => print_error!(e) @@ -572,7 +569,7 @@ fn handle_login(req: HttpRequest, mut params: web::Form) -> HttpRes let global_vars = req.app_data::>>>().unwrap(); on_identity_loaded(identity, global_vars) } - Err(e) => generate_login_response(Some(&e.to_string())) + Err(e) => generate_login_response(Some(&e)) }; params.password.zeroize(); response @@ -621,7 +618,7 @@ async fn handle_create(req: HttpRequest, mut params: web::Form) -> let response = if params.password == params.password_confirm { match Identity::create_identidy( ¶ms.name, - if params.password.len() == 0 { //no password + if params.password.is_empty() { //no password None } else { Some(params.password.as_bytes()) @@ -693,7 +690,7 @@ fn replace_fields(file_path: &str) -> String { } fn handle_static(req: HttpRequest) -> HttpResponse { - let splits: Vec<&str> = req.path()[1..].split("/").collect(); + let splits: Vec<&str> = req.path()[1..].split('/').collect(); if splits[0] == "static" { let mut response_builder = HttpResponse::Ok(); match splits[1] { @@ -717,7 +714,7 @@ fn handle_static(req: HttpRequest) -> HttpResponse { } else { "none" }; - match match splits[3] { + if let Some(body) = match splits[3] { "verified" => Some(include_str!("frontend/imgs/icons/verified.svg")), "add_contact" => Some(include_str!("frontend/imgs/icons/add_contact.svg")), "remove_contact" => Some(include_str!("frontend/imgs/icons/remove_contact.svg")), @@ -732,11 +729,8 @@ fn handle_static(req: HttpRequest) -> HttpResponse { "profile" => Some(include_str!("frontend/imgs/icons/profile.svg")), _ => None } { - Some(body) => { - response_builder.content_type("image/svg+xml"); - return response_builder.body(body.replace("FILL_COLOR", color)) - } - None => {} + response_builder.content_type("image/svg+xml"); + return response_builder.body(body.replace("FILL_COLOR", color)) } } else if splits.len() == 3 { match splits[2] { @@ -776,13 +770,12 @@ fn handle_static(req: HttpRequest) -> HttpResponse { } "libs" => { if splits.len() == 3 { - match match splits[2] { + if let Some(body) = match splits[2] { "linkify.min.js" => Some(include_str!("frontend/libs/linkify.min.js")), "linkify-element.min.js" => Some(include_str!("frontend/libs/linkify-element.min.js")), _ => None } { - Some(body) => return response_builder.content_type(JS_CONTENT_TYPE).body(body), - None => {} + return response_builder.content_type(JS_CONTENT_TYPE).body(body); } } } @@ -794,7 +787,7 @@ fn handle_static(req: HttpRequest) -> HttpResponse { #[actix_web::main] async fn start_http_server(global_vars: Arc>) -> io::Result<()> { - let http_addr = env::var("AIRA_HTTP_ADDR").unwrap_or("127.0.0.1".to_owned()).parse().expect("AIRA_HTTP_ADDR invalid"); + let http_addr = env::var("AIRA_HTTP_ADDR").unwrap_or_else(|_| "127.0.0.1".to_owned()).parse().expect("AIRA_HTTP_ADDR invalid"); let http_port = match env::var("AIRA_HTTP_PORT") { Ok(port) => port.parse().expect("AIRA_HTTP_PORT invalid"), Err(_) => constants::UI_PORT diff --git a/src/protocol.rs b/src/protocol.rs index c60543a..6896a3b 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -33,7 +33,7 @@ pub fn file(file_name: &str, buffer: &[u8]) -> Vec { [&[Headers::FILE], &(file_name.len() as u16).to_be_bytes()[..], file_name.as_bytes(), buffer].concat() } -pub fn get_file_name<'a>(buffer: &'a [u8]) -> Option<&'a str> { +pub fn get_file_name(buffer: &[u8]) -> Option<&str> { if buffer.len() > 3 { let file_name_len = u16::from_be_bytes([buffer[1], buffer[2]]) as usize; if buffer.len() > 3+file_name_len { @@ -43,7 +43,7 @@ pub fn get_file_name<'a>(buffer: &'a [u8]) -> Option<&'a str> { None } -pub fn parse_file<'a>(buffer: &'a [u8]) -> Option<(&'a str, &'a [u8])> { +pub fn parse_file(buffer: &[u8]) -> Option<(&str, &[u8])> { let file_name = get_file_name(buffer)?; Some((file_name, &buffer[3+file_name.len()..])) } diff --git a/src/session_manager.rs b/src/session_manager.rs index f0b5180..ab37407 100644 --- a/src/session_manager.rs +++ b/src/session_manager.rs @@ -65,11 +65,10 @@ impl SessionManager { fn with_ui_connection(&self, f: F) where F: FnOnce(&mut UiConnection) { let mut ui_connection_opt = self.ui_connection.lock().unwrap(); - match ui_connection_opt.as_mut() { - Some(ui_connection) => if ui_connection.is_valid { + if let Some(ui_connection) = ui_connection_opt.as_mut() { + if ui_connection.is_valid { f(ui_connection); } - None => {} } } @@ -110,10 +109,7 @@ impl SessionManager { fn get_session_sender(&self, session_id: &usize) -> Option> { let sessions = self.sessions.read().unwrap(); - match sessions.get(session_id) { - Some(session_data) => Some(session_data.sender.clone()), - None => None - } + sessions.get(session_id).map(|session_data| session_data.sender.clone()) } pub async fn send_command(&self, session_id: &usize, session_command: SessionCommand) -> bool { @@ -488,11 +484,9 @@ impl SessionManager { //don't send msg if we already encrypted a file chunk (keep PSEC nonces synchronized) if is_sending { msg_queue.push(buff); - } else { - if let Err(e) = self.send_msg(session_id, &mut session_write, buff, &mut is_sending, &mut file_ack_sender).await { - print_error!(e); - break; - } + } else if let Err(e) = self.send_msg(session_id, &mut session_write, buff, &mut is_sending, &mut file_ack_sender).await { + print_error!(e); + break; } } SessionCommand::EncryptFileChunk { plain_text } => { @@ -505,7 +499,7 @@ impl SessionManager { Ok(_) => { file_ack_sender = Some(ack_sender); //once the pre-encrypted chunk is sent, we can send the pending messages - while msg_queue.len() > 0 { + while !msg_queue.is_empty() { let msg = msg_queue.remove(0); if let Err(e) = self.send_msg(session_id, &mut session_write, msg, &mut is_sending, &mut file_ack_sender).await { print_error!(e); @@ -594,7 +588,7 @@ impl SessionManager { outgoing, peer_public_key, ip, - sender: sender, + sender, files_download: None, }; let mut session_id = None; @@ -675,16 +669,13 @@ impl SessionManager { } let mut loaded_contacts = self.loaded_contacts.write().unwrap(); - match loaded_contacts.get_mut(&session_id) { - Some(contact) => { - if contact.seen != seen { - match self.identity.read().unwrap().as_ref().unwrap().set_contact_seen(&contact.uuid, seen) { - Ok(_) => contact.seen = seen, - Err(e) => print_error!(e) - } + if let Some(contact) = loaded_contacts.get_mut(&session_id) { + if contact.seen != seen { + match self.identity.read().unwrap().as_ref().unwrap().set_contact_seen(&contact.uuid, seen) { + Ok(_) => contact.seen = seen, + Err(e) => print_error!(e) } } - None => {} } } @@ -734,10 +725,10 @@ impl SessionManager { } pub fn store_file(&self, session_id: &usize, data: &[u8]) -> Result { - self.identity.read().unwrap().as_ref().unwrap().store_file(match self.loaded_contacts.read().unwrap().get(session_id) { - Some(contact) => Some(contact.uuid), - None => None - }, data) + self.identity.read().unwrap().as_ref().unwrap().store_file( + self.loaded_contacts.read().unwrap().get(session_id).map(|contact| contact.uuid), + data + ) } pub fn load_msgs(&self, session_id: &usize, count: usize) -> Option> { @@ -824,21 +815,18 @@ impl SessionManager { } *identity_guard = identity; if identity_guard.is_some() { //login - match identity_guard.as_ref().unwrap().load_contacts() { - Some(contacts) => { - let mut loaded_contacts = self.loaded_contacts.write().unwrap(); - let mut session_counter = self.session_counter.write().unwrap(); - let mut not_seen = self.not_seen.write().unwrap(); - contacts.into_iter().for_each(|contact| { - if !contact.seen { - not_seen.push(*session_counter); - } - loaded_contacts.insert(*session_counter, contact); - self.pending_msgs.lock().unwrap().insert(*session_counter, Vec::new()); - *session_counter += 1; - }) - } - None => {} + if let Some(contacts) = identity_guard.as_ref().unwrap().load_contacts() { + let mut loaded_contacts = self.loaded_contacts.write().unwrap(); + let mut session_counter = self.session_counter.write().unwrap(); + let mut not_seen = self.not_seen.write().unwrap(); + contacts.into_iter().for_each(|contact| { + if !contact.seen { + not_seen.push(*session_counter); + } + loaded_contacts.insert(*session_counter, contact); + self.pending_msgs.lock().unwrap().insert(*session_counter, Vec::new()); + *session_counter += 1; + }); } } } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 6a8c806..218ca75 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1,4 +1,4 @@ -use std::{fmt::Display, iter::FromIterator, net::{IpAddr, TcpStream}, str::from_utf8}; +use std::{fmt::Display, net::{IpAddr, TcpStream}, str::from_utf8}; use tungstenite::{WebSocket, protocol::Role, Message}; use uuid::Uuid; use crate::{identity, print_error, protocol, session_manager::{LargeFileDownload, LargeFilesDownload}, utils::to_uuid_bytes}; @@ -11,7 +11,7 @@ pub struct UiConnection{ impl UiConnection { pub fn new(websocket: WebSocket) -> UiConnection { UiConnection { - websocket: websocket, + websocket, is_valid: true } } @@ -26,14 +26,14 @@ impl UiConnection { self.write_message(format!("{} {}", command, session_id)); } fn data_list(command: &str, data: Vec) -> String { - command.to_string()+&String::from_iter(data.into_iter().map(|i| { + command.to_string()+&data.into_iter().map(|i| { format!(" {}", i) - })) + }).collect::() } - pub fn on_ask_large_files(&mut self, session_id: &usize, files: &Vec, download_location: &str) { + pub fn on_ask_large_files(&mut self, session_id: &usize, files: &[LargeFileDownload], download_location: &str) { let mut s = format!("ask_large_files {} {}", session_id, base64::encode(download_location)); - files.into_iter().for_each(|file| { + files.iter().for_each(|file| { s.push_str(&format!( " {} {}", base64::encode(&file.file_name), @@ -100,9 +100,9 @@ impl UiConnection { pub fn set_as_contact(&mut self, session_id: usize, name: &str, verified: bool, fingerprint: &str) { self.write_message(format!("is_contact {} {} {} {}", session_id, verified, fingerprint, name)); } - pub fn load_msgs(&mut self, session_id: &usize, msgs: &Vec) { + pub fn load_msgs(&mut self, session_id: &usize, msgs: &[identity::Message]) { let mut s = format!("load_msgs {}", session_id); - msgs.into_iter().rev().for_each(|message| { + msgs.iter().rev().for_each(|message| { match message.data[0] { protocol::Headers::MESSAGE => match from_utf8(&message.data[1..]) { Ok(msg) => s.push_str(&format!(" m {} {} {}", message.outgoing, message.timestamp, base64::encode(msg))), diff --git a/src/utils.rs b/src/utils.rs index afb4e88..60265f5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, time::{SystemTime, UNIX_EPOCH}, path::PathBuf}; +use std::{convert::TryInto, time::{SystemTime, UNIX_EPOCH}, path::Path}; use uuid::Bytes; use crate::print_error; @@ -24,7 +24,7 @@ pub fn get_unix_timestamp_sec() -> u64 { SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() } -pub fn get_not_used_path(file_name: &str, parent_directory: &PathBuf) -> String { +pub fn get_not_used_path(file_name: &str, parent_directory: &Path) -> String { let has_extension = file_name.matches('.').count() > 0; let mut path = parent_directory.join(&file_name); let mut n = 1;