Make cargo clippy happy

This commit is contained in:
Matéo Duparc 2021-08-18 16:09:52 +02:00
parent dce526922e
commit 5ae61222f4
Signed by: hardcoresushi
GPG Key ID: 007F84120107191E
8 changed files with 138 additions and 154 deletions

View File

@ -335,32 +335,35 @@ profileDiv.onclick = function() {
changePasswordButton.textContent = "Change password"; changePasswordButton.textContent = "Change password";
changePasswordButton.onclick = function() { changePasswordButton.onclick = function() {
let inputs = document.querySelectorAll("input[type=\"password\"]"); let inputs = document.querySelectorAll("input[type=\"password\"]");
let newPassword, newPasswordConfirm; let newPassword, newPasswordConfirm, oldPassword;
if (isIdentityProtected) { if (isIdentityProtected) {
newPassword = inputs[1]; oldPassword = inputs[0].value;
newPasswordConfirm = inputs[2]; newPassword = inputs[1].value;
newPasswordConfirm = inputs[2].value;
} else { } else {
newPassword = inputs[0]; newPassword = inputs[0].value;
newPasswordConfirm = inputs[1]; newPasswordConfirm = inputs[1].value;
} }
if (newPassword.value == newPasswordConfirm.value) { if (newPassword == newPasswordConfirm) {
let newPassword_set = newPassword.value.length > 0; let newPasswordSet = newPassword.length > 0;
if (isIdentityProtected || newPassword_set) { //don't change password if identity is not protected and new password is blank 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"; let msg = "change_password";
if (isIdentityProtected) { if (isIdentityProtected) {
msg += " "+b64EncodeUnicode(inputs[0].value); msg += " "+b64EncodeUnicode(inputs[0].value);
} }
if (newPassword_set) { if (newPasswordSet) {
msg += " "+b64EncodeUnicode(newPassword.value); msg += " "+b64EncodeUnicode(newPassword);
} }
socket.send(msg); socket.send(msg);
} else { } else {
removePopup(); removePopup();
} }
} else { } else {
newPassword.value = ""; newPassword = "";
newPasswordConfirm.value = ""; newPasswordConfirm = "";
errorMsg.textContent = "Passwords don't match"; errorMsg.textContent = "Passwords don't match.";
} }
}; };
sectionPassword.appendChild(changePasswordButton); sectionPassword.appendChild(changePasswordButton);

View File

@ -94,8 +94,8 @@ impl Identity {
}; };
Ok(Contact { Ok(Contact {
uuid: contact_uuid, uuid: contact_uuid,
public_key: public_key, public_key,
name: name, name,
avatar: avatar_uuid, avatar: avatar_uuid,
verified: false, verified: false,
seen: true, seen: true,
@ -277,27 +277,23 @@ impl Identity {
let encrypted_outgoing: Vec<u8> = row.get(0).unwrap(); let encrypted_outgoing: Vec<u8> = row.get(0).unwrap();
match crypto::decrypt_data(encrypted_outgoing.as_slice(), &self.master_key){ match crypto::decrypt_data(encrypted_outgoing.as_slice(), &self.master_key){
Ok(outgoing) => { Ok(outgoing) => {
match byte_to_bool(outgoing[0]) { if let Ok(outgoing) = byte_to_bool(outgoing[0]) {
Ok(outgoing) => { let encrypted_timestamp: Vec<u8> = row.get(1).unwrap();
let encrypted_timestamp: Vec<u8> = row.get(1).unwrap(); match crypto::decrypt_data(&encrypted_timestamp, &self.master_key) {
match crypto::decrypt_data(&encrypted_timestamp, &self.master_key) { Ok(timestamp) => {
Ok(timestamp) => { let encrypted_data: Vec<u8> = row.get(2).unwrap();
let encrypted_data: Vec<u8> = row.get(2).unwrap(); match crypto::decrypt_data(encrypted_data.as_slice(), &self.master_key) {
match crypto::decrypt_data(encrypted_data.as_slice(), &self.master_key) { Ok(data) => msgs.push(Message {
Ok(data) => msgs.push(Message { outgoing,
outgoing, timestamp: u64::from_be_bytes(timestamp.try_into().unwrap()),
timestamp: u64::from_be_bytes(timestamp.try_into().unwrap()), data,
data, }),
}), Err(e) => print_error!(e)
Err(e) => print_error!(e)
}
} }
Err(e) => print_error!(e)
} }
Err(e) => print_error!(e)
} }
Err(_) => {}
} }
} }
Err(e) => print_error!(e) Err(e) => print_error!(e)
} }
@ -382,14 +378,8 @@ impl Identity {
pub fn load_identity(password: Option<&[u8]>) -> Result<Identity, String> { pub fn load_identity(password: Option<&[u8]>) -> Result<Identity, String> {
match Identity::load_encrypted_identity() { match Identity::load_encrypted_identity() {
Ok(encrypted_identity) => { Ok(encrypted_identity) => {
let master_key: [u8; crypto::MASTER_KEY_LEN] = if password.is_none() { let master_key: [u8; crypto::MASTER_KEY_LEN] = match password {
if encrypted_identity.encrypted_master_key.len() == crypto::MASTER_KEY_LEN { Some(password) => match crypto::decrypt_master_key(&encrypted_identity.encrypted_master_key, password, &encrypted_identity.salt) {
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) {
Ok(master_key) => master_key, Ok(master_key) => master_key,
Err(e) => return Err( Err(e) => return Err(
match e { 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) { match crypto::decrypt_data(&encrypted_identity.encrypted_keypair, &master_key) {
Ok(keypair) => { Ok(keypair) => {
@ -443,13 +438,16 @@ impl Identity {
let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?; let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?;
db.set(DBKeys::NAME, name.as_bytes())?; db.set(DBKeys::NAME, name.as_bytes())?;
db.set(DBKeys::KEYPAIR, &encrypted_keypair)?; db.set(DBKeys::KEYPAIR, &encrypted_keypair)?;
let salt = if password.is_none() { //no password let salt = match password {
db.set(DBKeys::MASTER_KEY, &master_key)?; //storing master_key in plaintext Some(password) => {
[0; crypto::SALT_LEN] let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, password);
} else { db.set(DBKeys::MASTER_KEY, &encrypted_master_key)?;
let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, password.unwrap()); salt
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)?; db.set(DBKeys::SALT, &salt)?;
let encrypted_use_padding = crypto::encrypt_data(&[bool_to_byte(true)], &master_key).unwrap(); 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<usize, rusqlite::Error> { fn update_master_key(master_key: [u8; crypto::MASTER_KEY_LEN], new_password: Option<&[u8]>) -> Result<usize, rusqlite::Error> {
let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?; let db = KeyValueTable::new(&get_database_path(), MAIN_TABLE)?;
let salt = if new_password.is_none() { //no password let salt = match new_password {
db.update(DBKeys::MASTER_KEY, &master_key)?; Some(new_password) => {
[0; crypto::SALT_LEN] let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, new_password);
} else { db.update(DBKeys::MASTER_KEY, &encrypted_master_key)?;
let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, new_password.unwrap()); salt
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) db.update(DBKeys::SALT, &salt)
} }
@ -478,20 +479,19 @@ impl Identity {
pub fn change_password(old_password: Option<&[u8]>, new_password: Option<&[u8]>) -> Result<bool, String> { pub fn change_password(old_password: Option<&[u8]>, new_password: Option<&[u8]>) -> Result<bool, String> {
match Identity::load_encrypted_identity() { match Identity::load_encrypted_identity() {
Ok(encrypted_identity) => { Ok(encrypted_identity) => {
let master_key: [u8; crypto::MASTER_KEY_LEN] = if old_password.is_none() { let master_key: [u8; crypto::MASTER_KEY_LEN] = match old_password {
if encrypted_identity.encrypted_master_key.len() == crypto::MASTER_KEY_LEN { Some(old_password) => match crypto::decrypt_master_key(&encrypted_identity.encrypted_master_key, old_password, &encrypted_identity.salt) {
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) {
Ok(master_key) => master_key, Ok(master_key) => master_key,
Err(e) => return match e { Err(e) => return match e {
CryptoError::DecryptionFailed => Ok(false), CryptoError::DecryptionFailed => Ok(false),
CryptoError::InvalidLength => Err(String::from(DATABASE_CORRUPED_ERROR)) 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) { match Identity::update_master_key(master_key, new_password) {
Ok(_) => Ok(true), Ok(_) => Ok(true),

View File

@ -12,7 +12,7 @@ impl<'a> KeyValueTable<'a> {
Ok(KeyValueTable {db, table_name}) Ok(KeyValueTable {db, table_name})
} }
pub fn set(&self, key: &str, value: &[u8]) -> Result<usize, Error> { pub fn set(&self, key: &str, value: &[u8]) -> Result<usize, Error> {
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<Vec<u8>, Error> { pub fn get(&self, key: &str) -> Result<Vec<u8>, Error> {
let mut stmt = self.db.prepare(&format!("SELECT value FROM {} WHERE key=\"{}\"", self.table_name, key))?; let mut stmt = self.db.prepare(&format!("SELECT value FROM {} WHERE key=\"{}\"", self.table_name, key))?;

View File

@ -8,7 +8,7 @@ mod ui_interface;
mod constants; mod constants;
mod discovery; 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 image::GenericImageView;
use tokio::{net::TcpListener, runtime::Handle, sync::mpsc}; use tokio::{net::TcpListener, runtime::Handle, sync::mpsc};
use actix_web::{App, HttpMessage, HttpRequest, HttpResponse, HttpServer, http::{header, CookieBuilder}, web, web::Data}; 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; use ui_interface::UiConnection;
async fn start_websocket_server(global_vars: Arc<RwLock<GlobalVars>>) -> u16 { async fn start_websocket_server(global_vars: Arc<RwLock<GlobalVars>>) -> u16 {
let websocket_bind_addr = env::var("AIRA_WEBSOCKET_ADDR").unwrap_or("127.0.0.1".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("0".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 server = TcpListener::bind(websocket_bind_addr+":"+&websocket_port).await.unwrap();
let websocket_port = server.local_addr().unwrap().port(); let websocket_port = server.local_addr().unwrap().port();
tokio::spawn(async move { tokio::spawn(async move {
@ -114,7 +114,7 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
} }
} }
session_manager.get_saved_msgs().into_iter().for_each(|msgs| { session_manager.get_saved_msgs().into_iter().for_each(|msgs| {
if msgs.1.len() > 0 { if !msgs.1.is_empty() {
ui_connection.load_msgs(&msgs.0, &msgs.1); ui_connection.load_msgs(&msgs.0, &msgs.1);
} }
}); });
@ -157,7 +157,7 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
let mut ui_connection = ui_connection.clone(); let mut ui_connection = ui_connection.clone();
let session_manager = session_manager.clone(); let session_manager = session_manager.clone();
handle.spawn(async move { handle.spawn(async move {
let args: Vec<&str> = msg.split(" ").collect(); let args: Vec<&str> = msg.split_whitespace().collect();
match args[0] { match args[0] {
"set_seen" => { "set_seen" => {
let session_id: usize = args[1].parse().unwrap(); let session_id: usize = args[1].parse().unwrap();
@ -177,9 +177,11 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
let msg_content = &msg[args[0].len()+args[1].len()+2..]; let msg_content = &msg[args[0].len()+args[1].len()+2..];
let buffer = protocol::new_message(msg_content); let buffer = protocol::new_message(msg_content);
#[allow(unused_must_use)] { #[allow(unused_must_use)] {
session_manager.send_or_add_to_pending(&session_id, buffer).await.map(|sent| if !sent { if let Ok(sent) = session_manager.send_or_add_to_pending(&session_id, buffer).await {
ui_connection.new_pending_msg(&session_id, false, msg_content); if !sent {
}); ui_connection.new_pending_msg(&session_id, false, msg_content);
}
}
} }
} }
"large_files" => { "large_files" => {
@ -274,11 +276,11 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
(None, Some(base64::decode(args[1]).unwrap())) (None, Some(base64::decode(args[1]).unwrap()))
}; };
let result = Identity::change_password(old_password.as_deref(), new_password.as_deref()); let result = Identity::change_password(old_password.as_deref(), new_password.as_deref());
if old_password.is_some() { if let Some(mut old_password) = old_password {
old_password.unwrap().zeroize(); old_password.zeroize();
} }
let is_identity_protected = if new_password.is_some() { let is_identity_protected = if let Some(mut new_password) = new_password {
new_password.unwrap().zeroize(); new_password.zeroize();
true true
} else { } else {
false false
@ -337,12 +339,10 @@ async fn handle_set_avatar(req: HttpRequest, mut payload: Multipart) -> HttpResp
match image::load_from_memory_with_format(&buffer, format) { match image::load_from_memory_with_format(&buffer, format) {
Ok(image) => { Ok(image) => {
let (width, height) = image.dimensions(); let (width, height) = image.dimensions();
let image = if width < height { let image = match width.cmp(&height) {
image.crop_imm(0, (height-width)/2, width, width) Ordering::Greater => image.crop_imm((width-height)/2, 0, height, height),
} else if width > height { Ordering::Less => image.crop_imm(0, (height-width)/2, width, width),
image.crop_imm((width-height)/2, 0, height, height) Ordering::Equal => image,
} else {
image
}; };
let mut avatar = Vec::new(); let mut avatar = Vec::new();
image.write_to(&mut avatar, format).unwrap(); image.write_to(&mut avatar, format).unwrap();
@ -385,7 +385,7 @@ fn reply_with_avatar(avatar: Option<Vec<u8>>, name: Option<&str>) -> HttpRespons
let svg = include_str!(concat!(env!("OUT_DIR"), "/text_avatar.svg")); let svg = include_str!(concat!(env!("OUT_DIR"), "/text_avatar.svg"));
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let svg = replace_fields("src/frontend/imgs/text_avatar.svg"); 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() None => HttpResponse::InternalServerError().finish()
} }
@ -393,7 +393,7 @@ fn reply_with_avatar(avatar: Option<Vec<u8>>, name: Option<&str>) -> HttpRespons
} }
fn handle_avatar(req: HttpRequest) -> HttpResponse { 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.len() == 2 {
if splits[1] == "self" { if splits[1] == "self" {
return reply_with_avatar(Identity::get_identity_avatar().ok(), Identity::get_identity_name().ok().as_deref()); 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<FileInfo>) -> HttpRe
match Uuid::from_str(&file_info.uuid) { match Uuid::from_str(&file_info.uuid) {
Ok(uuid) => { Ok(uuid) => {
let global_vars = req.app_data::<Data<Arc<RwLock<GlobalVars>>>>().unwrap(); let global_vars = req.app_data::<Data<Arc<RwLock<GlobalVars>>>>().unwrap();
match global_vars.read().unwrap().session_manager.identity.read().unwrap().as_ref().unwrap().load_file(uuid) { if let Some(buffer) = 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);
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 => {}
} }
} }
Err(e) => print_error!(e) Err(e) => print_error!(e)
@ -572,7 +569,7 @@ fn handle_login(req: HttpRequest, mut params: web::Form<LoginParams>) -> HttpRes
let global_vars = req.app_data::<Data<Arc<RwLock<GlobalVars>>>>().unwrap(); let global_vars = req.app_data::<Data<Arc<RwLock<GlobalVars>>>>().unwrap();
on_identity_loaded(identity, global_vars) 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(); params.password.zeroize();
response response
@ -621,7 +618,7 @@ async fn handle_create(req: HttpRequest, mut params: web::Form<CreateParams>) ->
let response = if params.password == params.password_confirm { let response = if params.password == params.password_confirm {
match Identity::create_identidy( match Identity::create_identidy(
&params.name, &params.name,
if params.password.len() == 0 { //no password if params.password.is_empty() { //no password
None None
} else { } else {
Some(params.password.as_bytes()) Some(params.password.as_bytes())
@ -693,7 +690,7 @@ fn replace_fields(file_path: &str) -> String {
} }
fn handle_static(req: HttpRequest) -> HttpResponse { 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" { if splits[0] == "static" {
let mut response_builder = HttpResponse::Ok(); let mut response_builder = HttpResponse::Ok();
match splits[1] { match splits[1] {
@ -717,7 +714,7 @@ fn handle_static(req: HttpRequest) -> HttpResponse {
} else { } else {
"none" "none"
}; };
match match splits[3] { if let Some(body) = match splits[3] {
"verified" => Some(include_str!("frontend/imgs/icons/verified.svg")), "verified" => Some(include_str!("frontend/imgs/icons/verified.svg")),
"add_contact" => Some(include_str!("frontend/imgs/icons/add_contact.svg")), "add_contact" => Some(include_str!("frontend/imgs/icons/add_contact.svg")),
"remove_contact" => Some(include_str!("frontend/imgs/icons/remove_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")), "profile" => Some(include_str!("frontend/imgs/icons/profile.svg")),
_ => None _ => None
} { } {
Some(body) => { response_builder.content_type("image/svg+xml");
response_builder.content_type("image/svg+xml"); return response_builder.body(body.replace("FILL_COLOR", color))
return response_builder.body(body.replace("FILL_COLOR", color))
}
None => {}
} }
} else if splits.len() == 3 { } else if splits.len() == 3 {
match splits[2] { match splits[2] {
@ -776,13 +770,12 @@ fn handle_static(req: HttpRequest) -> HttpResponse {
} }
"libs" => { "libs" => {
if splits.len() == 3 { 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.min.js" => Some(include_str!("frontend/libs/linkify.min.js")),
"linkify-element.min.js" => Some(include_str!("frontend/libs/linkify-element.min.js")), "linkify-element.min.js" => Some(include_str!("frontend/libs/linkify-element.min.js")),
_ => None _ => None
} { } {
Some(body) => return response_builder.content_type(JS_CONTENT_TYPE).body(body), return response_builder.content_type(JS_CONTENT_TYPE).body(body);
None => {}
} }
} }
} }
@ -794,7 +787,7 @@ fn handle_static(req: HttpRequest) -> HttpResponse {
#[actix_web::main] #[actix_web::main]
async fn start_http_server(global_vars: Arc<RwLock<GlobalVars>>) -> io::Result<()> { async fn start_http_server(global_vars: Arc<RwLock<GlobalVars>>) -> 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") { let http_port = match env::var("AIRA_HTTP_PORT") {
Ok(port) => port.parse().expect("AIRA_HTTP_PORT invalid"), Ok(port) => port.parse().expect("AIRA_HTTP_PORT invalid"),
Err(_) => constants::UI_PORT Err(_) => constants::UI_PORT

View File

@ -33,7 +33,7 @@ pub fn file(file_name: &str, buffer: &[u8]) -> Vec<u8> {
[&[Headers::FILE], &(file_name.len() as u16).to_be_bytes()[..], file_name.as_bytes(), buffer].concat() [&[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 { if buffer.len() > 3 {
let file_name_len = u16::from_be_bytes([buffer[1], buffer[2]]) as usize; let file_name_len = u16::from_be_bytes([buffer[1], buffer[2]]) as usize;
if buffer.len() > 3+file_name_len { if buffer.len() > 3+file_name_len {
@ -43,7 +43,7 @@ pub fn get_file_name<'a>(buffer: &'a [u8]) -> Option<&'a str> {
None 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)?; let file_name = get_file_name(buffer)?;
Some((file_name, &buffer[3+file_name.len()..])) Some((file_name, &buffer[3+file_name.len()..]))
} }

View File

@ -65,11 +65,10 @@ impl SessionManager {
fn with_ui_connection<F>(&self, f: F) where F: FnOnce(&mut UiConnection) { fn with_ui_connection<F>(&self, f: F) where F: FnOnce(&mut UiConnection) {
let mut ui_connection_opt = self.ui_connection.lock().unwrap(); let mut ui_connection_opt = self.ui_connection.lock().unwrap();
match ui_connection_opt.as_mut() { if let Some(ui_connection) = ui_connection_opt.as_mut() {
Some(ui_connection) => if ui_connection.is_valid { if ui_connection.is_valid {
f(ui_connection); f(ui_connection);
} }
None => {}
} }
} }
@ -110,10 +109,7 @@ impl SessionManager {
fn get_session_sender(&self, session_id: &usize) -> Option<Sender<SessionCommand>> { fn get_session_sender(&self, session_id: &usize) -> Option<Sender<SessionCommand>> {
let sessions = self.sessions.read().unwrap(); let sessions = self.sessions.read().unwrap();
match sessions.get(session_id) { sessions.get(session_id).map(|session_data| session_data.sender.clone())
Some(session_data) => Some(session_data.sender.clone()),
None => None
}
} }
pub async fn send_command(&self, session_id: &usize, session_command: SessionCommand) -> bool { 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) //don't send msg if we already encrypted a file chunk (keep PSEC nonces synchronized)
if is_sending { if is_sending {
msg_queue.push(buff); msg_queue.push(buff);
} else { } else if let Err(e) = self.send_msg(session_id, &mut session_write, buff, &mut is_sending, &mut file_ack_sender).await {
if let Err(e) = self.send_msg(session_id, &mut session_write, buff, &mut is_sending, &mut file_ack_sender).await { print_error!(e);
print_error!(e); break;
break;
}
} }
} }
SessionCommand::EncryptFileChunk { plain_text } => { SessionCommand::EncryptFileChunk { plain_text } => {
@ -505,7 +499,7 @@ impl SessionManager {
Ok(_) => { Ok(_) => {
file_ack_sender = Some(ack_sender); file_ack_sender = Some(ack_sender);
//once the pre-encrypted chunk is sent, we can send the pending messages //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); 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 { if let Err(e) = self.send_msg(session_id, &mut session_write, msg, &mut is_sending, &mut file_ack_sender).await {
print_error!(e); print_error!(e);
@ -594,7 +588,7 @@ impl SessionManager {
outgoing, outgoing,
peer_public_key, peer_public_key,
ip, ip,
sender: sender, sender,
files_download: None, files_download: None,
}; };
let mut session_id = None; let mut session_id = None;
@ -675,16 +669,13 @@ impl SessionManager {
} }
let mut loaded_contacts = self.loaded_contacts.write().unwrap(); let mut loaded_contacts = self.loaded_contacts.write().unwrap();
match loaded_contacts.get_mut(&session_id) { if let Some(contact) = loaded_contacts.get_mut(&session_id) {
Some(contact) => { if contact.seen != seen {
if contact.seen != seen { match self.identity.read().unwrap().as_ref().unwrap().set_contact_seen(&contact.uuid, seen) {
match self.identity.read().unwrap().as_ref().unwrap().set_contact_seen(&contact.uuid, seen) { Ok(_) => contact.seen = seen,
Ok(_) => contact.seen = seen, Err(e) => print_error!(e)
Err(e) => print_error!(e)
}
} }
} }
None => {}
} }
} }
@ -734,10 +725,10 @@ impl SessionManager {
} }
pub fn store_file(&self, session_id: &usize, data: &[u8]) -> Result<Uuid, rusqlite::Error> { pub fn store_file(&self, session_id: &usize, data: &[u8]) -> Result<Uuid, rusqlite::Error> {
self.identity.read().unwrap().as_ref().unwrap().store_file(match self.loaded_contacts.read().unwrap().get(session_id) { self.identity.read().unwrap().as_ref().unwrap().store_file(
Some(contact) => Some(contact.uuid), self.loaded_contacts.read().unwrap().get(session_id).map(|contact| contact.uuid),
None => None data
}, data) )
} }
pub fn load_msgs(&self, session_id: &usize, count: usize) -> Option<Vec<Message>> { pub fn load_msgs(&self, session_id: &usize, count: usize) -> Option<Vec<Message>> {
@ -824,21 +815,18 @@ impl SessionManager {
} }
*identity_guard = identity; *identity_guard = identity;
if identity_guard.is_some() { //login if identity_guard.is_some() { //login
match identity_guard.as_ref().unwrap().load_contacts() { if let Some(contacts) = identity_guard.as_ref().unwrap().load_contacts() {
Some(contacts) => { let mut loaded_contacts = self.loaded_contacts.write().unwrap();
let mut loaded_contacts = self.loaded_contacts.write().unwrap(); let mut session_counter = self.session_counter.write().unwrap();
let mut session_counter = self.session_counter.write().unwrap(); let mut not_seen = self.not_seen.write().unwrap();
let mut not_seen = self.not_seen.write().unwrap(); contacts.into_iter().for_each(|contact| {
contacts.into_iter().for_each(|contact| { if !contact.seen {
if !contact.seen { not_seen.push(*session_counter);
not_seen.push(*session_counter); }
} loaded_contacts.insert(*session_counter, contact);
loaded_contacts.insert(*session_counter, contact); self.pending_msgs.lock().unwrap().insert(*session_counter, Vec::new());
self.pending_msgs.lock().unwrap().insert(*session_counter, Vec::new()); *session_counter += 1;
*session_counter += 1; });
})
}
None => {}
} }
} }
} }

View File

@ -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 tungstenite::{WebSocket, protocol::Role, Message};
use uuid::Uuid; use uuid::Uuid;
use crate::{identity, print_error, protocol, session_manager::{LargeFileDownload, LargeFilesDownload}, utils::to_uuid_bytes}; use crate::{identity, print_error, protocol, session_manager::{LargeFileDownload, LargeFilesDownload}, utils::to_uuid_bytes};
@ -11,7 +11,7 @@ pub struct UiConnection{
impl UiConnection { impl UiConnection {
pub fn new(websocket: WebSocket<TcpStream>) -> UiConnection { pub fn new(websocket: WebSocket<TcpStream>) -> UiConnection {
UiConnection { UiConnection {
websocket: websocket, websocket,
is_valid: true is_valid: true
} }
} }
@ -26,14 +26,14 @@ impl UiConnection {
self.write_message(format!("{} {}", command, session_id)); self.write_message(format!("{} {}", command, session_id));
} }
fn data_list<T: Display>(command: &str, data: Vec<T>) -> String { fn data_list<T: Display>(command: &str, data: Vec<T>) -> String {
command.to_string()+&String::from_iter(data.into_iter().map(|i| { command.to_string()+&data.into_iter().map(|i| {
format!(" {}", i) format!(" {}", i)
})) }).collect::<String>()
} }
pub fn on_ask_large_files(&mut self, session_id: &usize, files: &Vec<LargeFileDownload>, 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)); 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!( s.push_str(&format!(
" {} {}", " {} {}",
base64::encode(&file.file_name), 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) { 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)); self.write_message(format!("is_contact {} {} {} {}", session_id, verified, fingerprint, name));
} }
pub fn load_msgs(&mut self, session_id: &usize, msgs: &Vec<identity::Message>) { pub fn load_msgs(&mut self, session_id: &usize, msgs: &[identity::Message]) {
let mut s = format!("load_msgs {}", session_id); 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] { match message.data[0] {
protocol::Headers::MESSAGE => match from_utf8(&message.data[1..]) { protocol::Headers::MESSAGE => match from_utf8(&message.data[1..]) {
Ok(msg) => s.push_str(&format!(" m {} {} {}", message.outgoing, message.timestamp, base64::encode(msg))), Ok(msg) => s.push_str(&format!(" m {} {} {}", message.outgoing, message.timestamp, base64::encode(msg))),

View File

@ -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 uuid::Bytes;
use crate::print_error; use crate::print_error;
@ -24,7 +24,7 @@ pub fn get_unix_timestamp_sec() -> u64 {
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() 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 has_extension = file_name.matches('.').count() > 0;
let mut path = parent_directory.join(&file_name); let mut path = parent_directory.join(&file_name);
let mut n = 1; let mut n = 1;