diff --git a/src/client_server/account.rs b/src/client_server/account.rs index 24b04d5..0cf30a0 100644 --- a/src/client_server/account.rs +++ b/src/client_server/account.rs @@ -179,12 +179,11 @@ pub async fn register_route( let password = if is_guest { None } else { - body.password.clone() - } - .unwrap_or_default(); + body.password.as_deref() + }; // Create user - db.users.create(&user_id, &password)?; + db.users.create(&user_id, password)?; // Initial data db.account_data.update( @@ -233,7 +232,7 @@ pub async fn register_route( let conduit_user = UserId::parse_with_server_name("conduit", db.globals.server_name()) .expect("@conduit:server_name is valid"); - db.users.create(&conduit_user, "")?; + db.users.create(&conduit_user, None)?; let room_id = RoomId::new(db.globals.server_name()); @@ -547,7 +546,8 @@ pub async fn change_password_route( return Err(Error::Uiaa(uiaainfo)); } - db.users.set_password(&sender_user, &body.new_password)?; + db.users + .set_password(&sender_user, Some(&body.new_password))?; if body.logout_devices { // Logout all devices except the current one diff --git a/src/client_server/media.rs b/src/client_server/media.rs index f9350e0..74ca6c8 100644 --- a/src/client_server/media.rs +++ b/src/client_server/media.rs @@ -38,7 +38,11 @@ pub async fn create_content_route( ); db.media.create( mxc.clone(), - &body.filename.as_deref(), + &body + .filename + .as_ref() + .map(|filename| "inline; filename=".to_owned() + filename) + .as_deref(), &body.content_type.as_deref(), &body.file, )?; @@ -64,7 +68,7 @@ pub async fn get_content_route( let mxc = format!("mxc://{}/{}", body.server_name, body.media_id); if let Some(FileMeta { - filename, + content_disposition, content_type, file, }) = db.media.get(&mxc)? @@ -72,7 +76,7 @@ pub async fn get_content_route( Ok(get_content::Response { file, content_type, - content_disposition: filename, + content_disposition, } .into()) } else if &*body.server_name != db.globals.server_name() && body.allow_remote { diff --git a/src/database.rs b/src/database.rs index 561b561..7a55b03 100644 --- a/src/database.rs +++ b/src/database.rs @@ -11,7 +11,7 @@ pub mod transaction_ids; pub mod uiaa; pub mod users; -use crate::{Error, Result}; +use crate::{utils, Error, Result}; use directories::ProjectDirs; use futures::StreamExt; use log::{error, info}; @@ -246,6 +246,25 @@ impl Database { info!("Migration: 0 -> 1 finished"); } + if db.globals.database_version()? < 2 { + // We accidentally inserted hashed versions of "" into the db instead of just "" + for userid_password in db.users.userid_password.iter() { + let (userid, password) = userid_password?; + + let password = utils::string_from_bytes(&password); + + if password.map_or(false, |password| { + argon2::verify_encoded(&password, b"").unwrap_or(false) + }) { + db.users.userid_password.insert(userid, b"")?; + } + } + + db.globals.bump_database_version(2)?; + + info!("Migration: 1 -> 2 finished"); + } + // This data is probably outdated db.rooms.edus.presenceid_presence.clear()?; diff --git a/src/database/media.rs b/src/database/media.rs index 37fcb74..28ef88a 100644 --- a/src/database/media.rs +++ b/src/database/media.rs @@ -4,14 +4,14 @@ use crate::{utils, Error, Result}; use std::mem; pub struct FileMeta { - pub filename: Option, + pub content_disposition: Option, pub content_type: Option, pub file: Vec, } #[derive(Clone)] pub struct Media { - pub(super) mediaid_file: sled::Tree, // MediaId = MXC + WidthHeight + Filename + ContentType + pub(super) mediaid_file: sled::Tree, // MediaId = MXC + WidthHeight + ContentDisposition + ContentType } impl Media { @@ -19,7 +19,7 @@ impl Media { pub fn create( &self, mxc: String, - filename: &Option<&str>, + content_disposition: &Option<&str>, content_type: &Option<&str>, file: &[u8], ) -> Result<()> { @@ -28,7 +28,12 @@ impl Media { key.extend_from_slice(&0_u32.to_be_bytes()); // Width = 0 if it's not a thumbnail key.extend_from_slice(&0_u32.to_be_bytes()); // Height = 0 if it's not a thumbnail key.push(0xff); - key.extend_from_slice(filename.as_ref().map(|f| f.as_bytes()).unwrap_or_default()); + key.extend_from_slice( + content_disposition + .as_ref() + .map(|f| f.as_bytes()) + .unwrap_or_default(), + ); key.push(0xff); key.extend_from_slice( content_type @@ -46,7 +51,7 @@ impl Media { pub fn upload_thumbnail( &self, mxc: String, - filename: &Option, + content_disposition: &Option, content_type: &Option, width: u32, height: u32, @@ -57,7 +62,12 @@ impl Media { key.extend_from_slice(&width.to_be_bytes()); key.extend_from_slice(&height.to_be_bytes()); key.push(0xff); - key.extend_from_slice(filename.as_ref().map(|f| f.as_bytes()).unwrap_or_default()); + key.extend_from_slice( + content_disposition + .as_ref() + .map(|f| f.as_bytes()) + .unwrap_or_default(), + ); key.push(0xff); key.extend_from_slice( content_type @@ -92,20 +102,24 @@ impl Media { }) .transpose()?; - let filename_bytes = parts + let content_disposition_bytes = parts .next() .ok_or_else(|| Error::bad_database("Media ID in db is invalid."))?; - let filename = if filename_bytes.is_empty() { + let content_disposition = if content_disposition_bytes.is_empty() { None } else { - Some(utils::string_from_bytes(filename_bytes).map_err(|_| { - Error::bad_database("Filename in mediaid_file is invalid unicode.") - })?) + Some( + utils::string_from_bytes(content_disposition_bytes).map_err(|_| { + Error::bad_database( + "Content Disposition in mediaid_file is invalid unicode.", + ) + })?, + ) }; Ok(Some(FileMeta { - filename, + content_disposition, content_type, file: file.to_vec(), })) @@ -169,21 +183,22 @@ impl Media { }) .transpose()?; - let filename_bytes = parts + let content_disposition_bytes = parts .next() .ok_or_else(|| Error::bad_database("Media ID in db is invalid."))?; - let filename = if filename_bytes.is_empty() { + let content_disposition = if content_disposition_bytes.is_empty() { None } else { Some( - utils::string_from_bytes(filename_bytes) - .map_err(|_| Error::bad_database("Filename in db is invalid."))?, + utils::string_from_bytes(content_disposition_bytes).map_err(|_| { + Error::bad_database("Content Disposition in db is invalid.") + })?, ) }; Ok(Some(FileMeta { - filename, + content_disposition, content_type, file: file.to_vec(), })) @@ -202,16 +217,20 @@ impl Media { }) .transpose()?; - let filename_bytes = parts + let content_disposition_bytes = parts .next() .ok_or_else(|| Error::bad_database("Media ID in db is invalid."))?; - let filename = if filename_bytes.is_empty() { + let content_disposition = if content_disposition_bytes.is_empty() { None } else { - Some(utils::string_from_bytes(filename_bytes).map_err(|_| { - Error::bad_database("Filename in mediaid_file is invalid unicode.") - })?) + Some( + utils::string_from_bytes(content_disposition_bytes).map_err(|_| { + Error::bad_database( + "Content Disposition in mediaid_file is invalid unicode.", + ) + })?, + ) }; if let Ok(image) = image::load_from_memory(&file) { @@ -219,7 +238,7 @@ impl Media { let original_height = image.height(); if width > original_width || height > original_height { return Ok(Some(FileMeta { - filename, + content_disposition, content_type, file: file.to_vec(), })); @@ -286,14 +305,14 @@ impl Media { self.mediaid_file.insert(thumbnail_key, &*thumbnail_bytes)?; Ok(Some(FileMeta { - filename, + content_disposition, content_type, file: thumbnail_bytes.to_vec(), })) } else { // Couldn't parse file to generate thumbnail, send original Ok(Some(FileMeta { - filename, + content_disposition, content_type, file: file.to_vec(), })) diff --git a/src/database/users.rs b/src/database/users.rs index a5b8775..52e6e33 100644 --- a/src/database/users.rs +++ b/src/database/users.rs @@ -49,7 +49,7 @@ impl Users { } /// Create a new user account on this homeserver. - pub fn create(&self, user_id: &UserId, password: &str) -> Result<()> { + pub fn create(&self, user_id: &UserId, password: Option<&str>) -> Result<()> { self.set_password(user_id, password)?; Ok(()) } @@ -110,15 +110,20 @@ impl Users { } /// Hash and set the user's password to the Argon2 hash - pub fn set_password(&self, user_id: &UserId, password: &str) -> Result<()> { - if let Ok(hash) = utils::calculate_hash(&password) { - self.userid_password.insert(user_id.to_string(), &*hash)?; - Ok(()) + pub fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()> { + if let Some(password) = password { + if let Ok(hash) = utils::calculate_hash(&password) { + self.userid_password.insert(user_id.to_string(), &*hash)?; + Ok(()) + } else { + Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Password does not meet the requirements.", + )) + } } else { - Err(Error::BadRequest( - ErrorKind::InvalidParam, - "Password does not meet the requirements.", - )) + self.userid_password.insert(user_id.to_string(), "")?; + Ok(()) } }