Merge branch 'account' into 'master'

Fix account and media bugs

See merge request famedly/conduit!97
next
Timo Kösters 2021-06-08 07:22:32 +00:00
commit 81715bd84d
6 changed files with 93 additions and 45 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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()?;

View File

@ -4,14 +4,14 @@ use crate::{utils, Error, Result};
use std::mem;
pub struct FileMeta {
pub filename: Option<String>,
pub content_disposition: Option<String>,
pub content_type: Option<String>,
pub file: Vec<u8>,
}
#[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<String>,
content_disposition: &Option<String>,
content_type: &Option<String>,
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(),
}))

View File

@ -725,8 +725,9 @@ impl Rooms {
.users
.iter()
.filter_map(|r| r.ok())
.filter(|user_id| self.is_joined(&user_id, &pdu.room_id).unwrap_or(false))
.filter(|user_id| user_id.server_name() == db.globals.server_name())
.filter(|user_id| !db.users.is_deactivated(user_id).unwrap_or(false))
.filter(|user_id| self.is_joined(&user_id, &pdu.room_id).unwrap_or(false))
{
// Don't notify the user of their own events
if user == pdu.sender {

View File

@ -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(())
}
}