Make cargo clippy happy
This commit is contained in:
parent
dce526922e
commit
5ae61222f4
@ -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);
|
||||||
|
@ -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,8 +277,7 @@ 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) => {
|
||||||
@ -295,9 +294,6 @@ impl Identity {
|
|||||||
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 {
|
|
||||||
let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, password.unwrap());
|
|
||||||
db.set(DBKeys::MASTER_KEY, &encrypted_master_key)?;
|
db.set(DBKeys::MASTER_KEY, &encrypted_master_key)?;
|
||||||
salt
|
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 {
|
|
||||||
let (salt, encrypted_master_key) = crypto::encrypt_master_key(master_key, new_password.unwrap());
|
|
||||||
db.update(DBKeys::MASTER_KEY, &encrypted_master_key)?;
|
db.update(DBKeys::MASTER_KEY, &encrypted_master_key)?;
|
||||||
salt
|
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),
|
||||||
|
@ -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))?;
|
||||||
|
61
src/main.rs
61
src/main.rs
@ -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 {
|
||||||
|
if !sent {
|
||||||
ui_connection.new_pending_msg(&session_id, false, msg_content);
|
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,12 +417,9 @@ 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(
|
||||||
¶ms.name,
|
¶ms.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,12 +729,9 @@ 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] {
|
||||||
"wallpaper" => return response_builder.content_type("image/jpeg").body(&include_bytes!("frontend/imgs/wallpaper.jpeg")[..]),
|
"wallpaper" => return response_builder.content_type("image/jpeg").body(&include_bytes!("frontend/imgs/wallpaper.jpeg")[..]),
|
||||||
@ -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
|
||||||
|
@ -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()..]))
|
||||||
}
|
}
|
||||||
|
@ -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,13 +484,11 @@ 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 } => {
|
||||||
last_chunks_sizes.as_mut().unwrap().push(plain_text.len() as u32);
|
last_chunks_sizes.as_mut().unwrap().push(plain_text.len() as u32);
|
||||||
next_chunk = Some(session_write.encrypt(&plain_text, self.identity.read().unwrap().as_ref().unwrap().use_padding));
|
next_chunk = Some(session_write.encrypt(&plain_text, self.identity.read().unwrap().as_ref().unwrap().use_padding));
|
||||||
@ -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,8 +669,7 @@ 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,
|
||||||
@ -684,8 +677,6 @@ impl SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_contact(&self, session_id: usize) -> Result<(), rusqlite::Error> {
|
pub fn add_contact(&self, session_id: usize) -> Result<(), rusqlite::Error> {
|
||||||
@ -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,8 +815,7 @@ 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();
|
||||||
@ -836,9 +826,7 @@ impl SessionManager {
|
|||||||
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 => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))),
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user