Merge branch 'account' into 'master'
Fix account and media bugs See merge request famedly/conduit!97
This commit is contained in:
commit
81715bd84d
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()?;
|
||||
|
||||
|
|
|
@ -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(),
|
||||
}))
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue