diff --git a/src/data.rs b/src/data.rs index 3ec3b44a..ef30e273 100644 --- a/src/data.rs +++ b/src/data.rs @@ -60,10 +60,15 @@ impl Data { .map(|bytes| utils::string_from_bytes(&bytes)) } + /// Removes a displayname. + pub fn displayname_remove(&self, user_id: &UserId) { + self.db.userid_displayname.remove(user_id).unwrap(); + } + /// Set a new displayname. pub fn displayname_set(&self, user_id: &UserId, displayname: Option) { self.db - .profile_displayname + .userid_displayname .insert(user_id.to_string(), &*displayname.unwrap_or_default()) .unwrap(); } @@ -71,16 +76,21 @@ impl Data { /// Get a the displayname of a user. pub fn displayname_get(&self, user_id: &UserId) -> Option { self.db - .profile_displayname + .userid_displayname .get(user_id.to_string()) .unwrap() .map(|bytes| utils::string_from_bytes(&bytes)) } + /// Removes a avatar_url. + pub fn avatar_url_remove(&self, user_id: &UserId) { + self.db.userid_avatar_url.remove(user_id).unwrap(); + } + /// Set a new avatar_url. pub fn avatar_url_set(&self, user_id: &UserId, avatar_url: String) { self.db - .profile_avatar_url + .userid_avatar_url .insert(user_id.to_string(), &*avatar_url) .unwrap(); } @@ -88,7 +98,7 @@ impl Data { /// Get a the avatar_url of a user. pub fn avatar_url_get(&self, user_id: &UserId) -> Option { self.db - .profile_avatar_url + .userid_avatar_url .get(user_id.to_string()) .unwrap() .map(|bytes| utils::string_from_bytes(&bytes)) diff --git a/src/database.rs b/src/database.rs index a6ddd552..bdfab5b1 100644 --- a/src/database.rs +++ b/src/database.rs @@ -52,8 +52,8 @@ impl MultiValue { pub struct Database { pub userid_password: sled::Tree, pub userid_deviceids: MultiValue, - pub profile_displayname: sled::Tree, - pub profile_avatar_url: sled::Tree, + pub userid_displayname: sled::Tree, + pub userid_avatar_url: sled::Tree, pub deviceid_token: sled::Tree, pub token_userid: sled::Tree, pub pduid_pdus: sled::Tree, @@ -77,8 +77,8 @@ impl Database { Self { userid_password: db.open_tree("userid_password").unwrap(), userid_deviceids: MultiValue(db.open_tree("userid_deviceids").unwrap()), - profile_displayname: db.open_tree("profile_displayname").unwrap(), - profile_avatar_url: db.open_tree("profile_avatar_url").unwrap(), + userid_displayname: db.open_tree("userid_displayname").unwrap(), + userid_avatar_url: db.open_tree("userid_avatar_url").unwrap(), deviceid_token: db.open_tree("deviceid_token").unwrap(), token_userid: db.open_tree("token_userid").unwrap(), pduid_pdus: db.open_tree("pduid_pdus").unwrap(), @@ -108,7 +108,7 @@ impl Database { ); } println!("# AccountData -> Displayname:"); - for (k, v) in self.profile_displayname.iter().map(|r| r.unwrap()) { + for (k, v) in self.userid_displayname.iter().map(|r| r.unwrap()) { println!( "{:?} -> {:?}", String::from_utf8_lossy(&k), @@ -116,7 +116,7 @@ impl Database { ); } println!("# AccountData -> AvatarURL:"); - for (k, v) in self.profile_avatar_url.iter().map(|r| r.unwrap()) { + for (k, v) in self.userid_avatar_url.iter().map(|r| r.unwrap()) { println!( "{:?} -> {:?}", String::from_utf8_lossy(&k), diff --git a/src/main.rs b/src/main.rs index 41c7e6c4..3bc1e4bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![feature(proc_macro_hygiene, decl_macro)] + mod data; mod database; mod pdu; @@ -88,7 +89,7 @@ fn register_route( .unwrap_or_else(|| utils::random_string(GUEST_NAME_LENGTH)), data.hostname() )) - .try_into() + .try_into() { Err(_) => { debug!("Username invalid"); @@ -152,7 +153,7 @@ fn login_route(data: State, body: Ruma) -> MatrixResult MatrixResult { } #[get( - "/_matrix/client/r0/user/<_user_id>/filter/<_filter_id>", - data = "" +"/_matrix/client/r0/user/<_user_id>/filter/<_filter_id>", +data = "" )] fn get_filter_route( body: Ruma, @@ -261,8 +262,8 @@ fn create_filter_route( } #[put( - "/_matrix/client/r0/user/<_user_id>/account_data/<_type>", - data = "" +"/_matrix/client/r0/user/<_user_id>/account_data/<_type>", +data = "" )] fn set_global_account_data_route( body: Ruma, @@ -274,8 +275,8 @@ fn set_global_account_data_route( } #[get( - "/_matrix/client/r0/user/<_user_id>/account_data/<_type>", - data = "" +"/_matrix/client/r0/user/<_user_id>/account_data/<_type>", +data = "" )] fn get_global_account_data_route( body: Ruma, @@ -297,25 +298,35 @@ fn set_displayname_route( _user_id: String, ) -> MatrixResult { let user_id = body.user_id.clone().expect("user is authenticated"); + + // Send error on None and accept Some("") as valid username + // Synapse returns a parsing error but the spec doesn't require this if body.displayname.is_none() { debug!("Request was missing the displayname payload."); return MatrixResult(Err(Error { kind: ErrorKind::MissingParam, - message: "Missing displayname".to_owned(), + message: "Missing displayname.".to_owned(), status_code: http::StatusCode::BAD_REQUEST, })); } - data.displayname_set(&user_id, body.displayname.clone()); - // TODO send a new m.room.member join event with the updated displayname - // TODO send a new m.presence event with the updated displayname + if let Some(displayname) = body.displayname { + if displayname == "" { + data.displayname_remove(&user_id); + } else { + data.displayname_set(&user_id, body.displayname.clone()); + // TODO send a new m.room.member join event with the updated displayname + // TODO send a new m.presence event with the updated displayname + + } + } MatrixResult(Ok(set_display_name::Response)) } #[get( - "/_matrix/client/r0/profile//displayname", - data = "" +"/_matrix/client/r0/profile//displayname", +data = "" )] fn get_displayname_route( data: State, @@ -323,20 +334,26 @@ fn get_displayname_route( user_id_raw: String, ) -> MatrixResult { let user_id = (*body).user_id.clone(); + if !data.user_exists(&user_id) { + // Return 404 if we don't have a profile for this id + debug!("Profile was not found."); + MatrixResult(Err(Error { + kind: ErrorKind::NotFound, + message: "Profile was not found".to_owned(), + status_code: http::StatusCode::NOT_FOUND, + })) + } if let Some(displayname) = data.displayname_get(&user_id) { return MatrixResult(Ok(get_display_name::Response { displayname: Some(displayname), })); } - // Return 404 if we don't have any - debug!("Profile was not found."); - MatrixResult(Err(Error { - kind: ErrorKind::NotFound, - message: "Profile was not found".to_owned(), - status_code: http::StatusCode::NOT_FOUND, + MatrixResult(Ok(get_display_name::Response { + displayname: None, })) } + #[put("/_matrix/client/r0/profile/<_user_id>/avatar_url", data = "")] fn set_avatar_url_route( data: State, @@ -344,21 +361,28 @@ fn set_avatar_url_route( _user_id: String, ) -> MatrixResult { let user_id = body.user_id.clone().expect("user is authenticated"); - if body.avatar_url == "" { - debug!("Request was missing the avatar_url payload."); + + if !body.avatar_url.starts_with("mxc://") { + debug!("Request contains an invalid avatar_url."); return MatrixResult(Err(Error { - kind: ErrorKind::MissingParam, + kind: ErrorKind::InvalidParam, message: "Missing avatar_url".to_owned(), status_code: http::StatusCode::BAD_REQUEST, })); } // TODO in the future when we can handle media uploads make sure that this url is our own server - // TODO also make sure this is mxc:// format + // TODO also make sure this is valid mxc:// format (not only starting with it) - data.avatar_url_set(&user_id, body.avatar_url.clone()); - // TODO send a new m.room.member join event with the updated avatar_url - // TODO send a new m.presence event with the updated avatar_url + + if body.avatar_url == "" { + data.avatar_url_remove(&user_id); + } else { + data.avatar_url_set(&user_id, body.displayname.clone()); + // TODO send a new m.room.member join event with the updated avatar_url + // TODO send a new m.presence event with the updated avatar_url + + } MatrixResult(Ok(set_avatar_url::Response)) } @@ -370,18 +394,23 @@ fn get_avatar_url_route( user_id_raw: String, ) -> MatrixResult { let user_id = (*body).user_id.clone(); + if !data.user_exists(&user_id) { + // Return 404 if we don't have a profile for this id + debug!("Profile was not found."); + MatrixResult(Err(Error { + kind: ErrorKind::NotFound, + message: "Profile was not found".to_owned(), + status_code: http::StatusCode::NOT_FOUND, + })) + } if let Some(avatar_url) = data.avatar_url_get(&user_id) { return MatrixResult(Ok(get_avatar_url::Response { avatar_url: Some(avatar_url), })); } - // Return 404 if we don't have a profile for this id - debug!("Profile was not found."); - MatrixResult(Err(Error { - kind: ErrorKind::NotFound, - message: "Profile was not found".to_owned(), - status_code: http::StatusCode::NOT_FOUND, + MatrixResult(Ok(get_avatar_url::Response { + avatar_url: None, })) } @@ -395,7 +424,7 @@ fn get_profile_route( let avatar_url = data.avatar_url_get(&user_id); let displayname = data.displayname_get(&user_id); - if avatar_url.is_some() && displayname.is_some() { + if avatar_url.is_some() || displayname.is_some() { return MatrixResult(Ok(get_profile::Response { avatar_url, displayname, @@ -498,8 +527,8 @@ fn get_alias_route(room_alias: String) -> MatrixResult { })); } } - .try_into() - .unwrap(); + .try_into() + .unwrap(); MatrixResult(Ok(get_alias::Response { room_id, @@ -606,8 +635,8 @@ fn get_protocols_route( } #[put( - "/_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id>", - data = "" +"/_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id>", +data = "" )] fn create_message_event_route( data: State, @@ -631,8 +660,8 @@ fn create_message_event_route( } #[put( - "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key>", - data = "" +"/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key>", +data = "" )] fn create_state_event_for_key_route( data: State, @@ -654,8 +683,8 @@ fn create_state_event_for_key_route( } #[put( - "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>", - data = "" +"/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>", +data = "" )] fn create_state_event_for_empty_key_route( data: State,