From 18bf67748c14c2ded3bd7112e38317153d93a577 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Tue, 26 May 2020 10:27:51 +0200 Subject: [PATCH 1/3] feat: redaction --- Cargo.lock | 126 ++++++++++++++++++------------------------ Cargo.toml | 11 ++-- src/client_server.rs | 82 ++++++++++++++++++++------- src/database/rooms.rs | 55 +++++++++++++++--- src/pdu.rs | 33 ++++++++++- src/server_server.rs | 4 +- 6 files changed, 204 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc478160..fc9840f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26c4f3195085c36ea8d24d32b2f828d23296a9370a28aa39d111f6f16bef9f3b" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -277,9 +277,9 @@ version = "0.3.0" source = "git+https://github.com/SergioBenitez/Devise.git?rev=e58b3ac9a#e58b3ac9afc3b6ff10a8aaf02a3e768a8f530089" dependencies = [ "bitflags", - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -421,9 +421,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -918,9 +918,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.56" +version = "0.9.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02309a7f127000ed50594f0b50ecc69e7c654e16d41b4e8156d1b3df8e0b52e" +checksum = "7410fef80af8ac071d4f63755c0ab89ac3df0fd1ea91f1d1f37cf5cec4395990" dependencies = [ "autocfg", "cc", @@ -1002,9 +1002,9 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -1045,9 +1045,9 @@ checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "proc-macro-hack" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" +checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" [[package]] name = "proc-macro-nested" @@ -1066,9 +1066,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.13" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" dependencies = [ "unicode-xid 0.2.0", ] @@ -1088,7 +1088,7 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", ] [[package]] @@ -1229,7 +1229,7 @@ dependencies = [ "time", "tokio", "toml", - "version_check 0.9.1", + "version_check 0.9.2", "yansi 0.5.0", ] @@ -1242,7 +1242,7 @@ dependencies = [ "indexmap", "quote 1.0.6", "rocket_http", - "version_check 0.9.1", + "version_check 0.9.2", "yansi 0.5.0", ] @@ -1277,7 +1277,7 @@ dependencies = [ "percent-encoding 2.1.0", "ruma-api-macros", "ruma-identifiers", - "ruma-serde 0.2.1", + "ruma-serde", "serde", "serde_json", "strum", @@ -1289,16 +1289,15 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52b82b4567b9af9b40a86f7778821c016ea961f55e4fee255f8f24bb28ee7452" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] name = "ruma-client-api" version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "082913ad135ca55ee06a55d295bea954982f2ac5e0150adc09024f5cbb8cb6cf" +source = "git+https://github.com/ruma/ruma-client-api.git#b064daf23dbf970933e83ce3b84a2563c5e646e7" dependencies = [ "http", "js_int", @@ -1306,7 +1305,7 @@ dependencies = [ "ruma-common", "ruma-events", "ruma-identifiers", - "ruma-serde 0.2.1", + "ruma-serde", "serde", "serde_json", "strum", @@ -1319,7 +1318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "253416d67b4bde281f2781424232a58a946a4f1c451d5f857a8d0705d58eaf2a" dependencies = [ "matches", - "ruma-serde 0.2.1", + "ruma-serde", "serde", "serde_json", ] @@ -1327,14 +1326,13 @@ dependencies = [ [[package]] name = "ruma-events" version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0afc6d4da07d10213478d32dc42b6222df0a1ea319e9ced9f8a341617952d909" +source = "git+https://github.com/ruma/ruma-events.git#a17714669da1db4aa7bf10948463bb964cf5058a" dependencies = [ "js_int", "ruma-common", "ruma-events-macros", "ruma-identifiers", - "ruma-serde 0.2.1", + "ruma-serde", "serde", "serde_json", ] @@ -1342,24 +1340,24 @@ dependencies = [ [[package]] name = "ruma-events-macros" version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc706c4a53cc54c3a198cfbcd7dfff20448599d84f90e636d96034d0df5a9ac9" +source = "git+https://github.com/ruma/ruma-events.git#a17714669da1db4aa7bf10948463bb964cf5058a" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] name = "ruma-federation-api" version = "0.0.1" -source = "git+https://github.com/ruma/ruma-federation-api.git?rev=ccbf216f39bbbaa59131cc200eae5bd18aa1947c#ccbf216f39bbbaa59131cc200eae5bd18aa1947c" +source = "git+https://github.com/ruma/ruma-federation-api.git?rev=4cf4aa6ef74b25ad8c14d99d7774129f023df163#4cf4aa6ef74b25ad8c14d99d7774129f023df163" dependencies = [ "js_int", + "matches", "ruma-api", "ruma-events", "ruma-identifiers", - "ruma-serde 0.1.3", + "ruma-serde", "serde", "serde_json", ] @@ -1376,23 +1374,9 @@ dependencies = [ [[package]] name = "ruma-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14edc0e2f5177c419e3b89060b1e94fb3af81b2f253783ac6967f14a7ec3911" -dependencies = [ - "dtoa", - "itoa", - "js_int", - "serde", - "serde_json", - "url", -] - -[[package]] -name = "ruma-serde" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd3d04c6755bae23101dec7426d044b773ef517932f23d5a6254c4caa1cfce3" +checksum = "8c71dabb8e2709ca4f59201cb72d7fe8d590e7e3f55feb348e851c18354938af" dependencies = [ "dtoa", "itoa", @@ -1520,9 +1504,9 @@ version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -1614,9 +1598,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ "heck", - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -1632,11 +1616,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.23" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" +checksum = "f14a640819f79b72a710c0be059dce779f9339ae046c8bef12c361d56702146f" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", "unicode-xid 0.2.0", ] @@ -1657,22 +1641,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5976891d6950b4f68477850b5b9e5aa64d955961466f9e174363f573e54e8ca7" +checksum = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab81dbd1cd69cd2ce22ecfbdd3bdb73334ba25350649408cc6c085f46d89573d" +checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -1714,9 +1698,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", ] [[package]] @@ -1782,7 +1766,7 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.1", + "version_check 0.9.2", ] [[package]] @@ -1852,9 +1836,9 @@ checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "version_check" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "want" @@ -1893,9 +1877,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", "wasm-bindgen-shared", ] @@ -1927,9 +1911,9 @@ version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a" dependencies = [ - "proc-macro2 1.0.13", + "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.23", + "syn 1.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 5a068f59..c864508e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,12 +14,12 @@ edition = "2018" [dependencies] rocket = { git = "https://github.com/SergioBenitez/Rocket.git", branch = "async", features = ["tls"] } http = "0.2.1" -ruma-client-api = "0.9.0" +ruma-client-api = { git = "https://github.com/ruma/ruma-client-api.git" } ruma-identifiers = { version = "0.16.1", features = ["rand"] } ruma-api = "0.16.1" -ruma-events = "0.21.2" +ruma-events = { git = "https://github.com/ruma/ruma-events.git" } ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git", rev = "1ca545cba8dfd43e0fc8e3c18e1311fb73390a97" } -ruma-federation-api = { git = "https://github.com/ruma/ruma-federation-api.git", rev = "ccbf216f39bbbaa59131cc200eae5bd18aa1947c" } +ruma-federation-api = { git = "https://github.com/ruma/ruma-federation-api.git", rev = "4cf4aa6ef74b25ad8c14d99d7774129f023df163" } log = "0.4.8" sled = "0.31.0" directories = "2.0.2" @@ -31,6 +31,9 @@ rand = "0.7.3" rust-argon2 = "0.8.2" reqwest = "0.10.4" base64 = "0.12.1" -thiserror = "1.0.18" +thiserror = "1.0.19" ruma-common = "0.1.2" image = { version = "0.23.4", default-features = false, features = ["jpeg", "png", "gif"] } + +[patch.crates-io] +ruma-events = { git = "https://github.com/ruma/ruma-events.git" } diff --git a/src/client_server.rs b/src/client_server.rs index 6812fdde..0701be1a 100644 --- a/src/client_server.rs +++ b/src/client_server.rs @@ -39,13 +39,13 @@ use ruma_client_api::{ to_device::{self, send_event_to_device}, typing::create_typing_event, uiaa::{AuthFlow, UiaaInfo, UiaaResponse}, - user_directory::search_users, + user_directory::search_users, redact::redact_event, }, unversioned::get_supported_versions, }; use ruma_events::{ collections::only::Event as EduEvent, - room::{guest_access, history_visibility, join_rules, member}, + room::{guest_access, history_visibility, join_rules, member, redaction}, EventJson, EventType, }; use ruma_identifiers::{RoomId, RoomVersionId, UserId}; @@ -517,6 +517,7 @@ pub fn set_displayname_route( .unwrap(), None, Some(user_id.to_string()), + None, &db.globals, ) .unwrap(); @@ -564,7 +565,7 @@ pub fn set_avatar_url_route( ) -> MatrixResult { let user_id = body.user_id.as_ref().expect("user is authenticated"); - if let avatar_url = &body.avatar_url { + if let Some(avatar_url) = &body.avatar_url { if !avatar_url.starts_with("mxc://") { debug!("Request contains an invalid avatar_url."); return MatrixResult(Err(Error { @@ -579,7 +580,7 @@ pub fn set_avatar_url_route( } db.users - .set_avatar_url(&user_id, Some(body.avatar_url.clone())) + .set_avatar_url(&user_id, body.avatar_url.clone()) .unwrap(); // Send a new membership event into all joined rooms @@ -591,7 +592,7 @@ pub fn set_avatar_url_route( user_id.clone(), EventType::RoomMember, serde_json::to_value(ruma_events::room::member::MemberEventContent { - avatar_url: Some(body.avatar_url.clone()), + avatar_url: body.avatar_url.clone(), ..serde_json::from_value::>( db.rooms .room_state(&room_id) @@ -608,6 +609,7 @@ pub fn set_avatar_url_route( .unwrap(), None, Some(user_id.to_string()), + None, &db.globals, ) .unwrap(); @@ -917,14 +919,15 @@ pub fn create_room_route( creator: user_id.clone(), federate: body .creation_content - .and_then(|c| c.federate) - .unwrap_or(true), - predecessor: None, // TODO: Check creation_content.predecessor once ruma has that + .as_ref() + .map_or(true, |c| c.federate), + predecessor: body.creation_content.as_ref().and_then(|c| c.predecessor.clone()), room_version: RoomVersionId::version_5(), }) .unwrap(), None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -945,6 +948,7 @@ pub fn create_room_route( .unwrap(), None, Some(user_id.to_string()), + None, &db.globals, ) .unwrap(); @@ -968,18 +972,8 @@ pub fn create_room_route( .expect("TODO: handle. we hope the client sends a valid power levels json") } else { serde_json::to_value(ruma_events::room::power_levels::PowerLevelsEventContent { - ban: 50.into(), - events: BTreeMap::new(), - events_default: 0.into(), - invite: 50.into(), - kick: 50.into(), - redact: 50.into(), - state_default: 50.into(), users, - users_default: 0.into(), - notifications: ruma_events::room::power_levels::NotificationPowerLevels { - room: 50.into(), - }, + ..Default::default() }) .unwrap() }; @@ -991,6 +985,7 @@ pub fn create_room_route( power_levels_content, None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -1016,6 +1011,7 @@ pub fn create_room_route( }, None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -1032,6 +1028,7 @@ pub fn create_room_route( .unwrap(), None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -1056,6 +1053,7 @@ pub fn create_room_route( }, None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -1071,10 +1069,11 @@ pub fn create_room_route( .append_pdu( room_id.clone(), user_id.clone(), - EventType::from(event_type), + event_type.clone(), serde_json::from_str(content.get()).unwrap(), None, state_key.clone(), + None, &db.globals, ) .unwrap(); @@ -1093,6 +1092,7 @@ pub fn create_room_route( .unwrap(), None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -1110,6 +1110,7 @@ pub fn create_room_route( .unwrap(), None, Some("".to_owned()), + None, &db.globals, ) .unwrap(); @@ -1132,6 +1133,7 @@ pub fn create_room_route( .unwrap(), None, Some(user.to_string()), + None, &db.globals, ) .unwrap(); @@ -1140,6 +1142,38 @@ pub fn create_room_route( MatrixResult(Ok(create_room::Response { room_id })) } +#[put("/_matrix/client/r0/rooms/<_room_id>/redact/<_event_id>/<_txn_id>", data = "")] +pub fn redact_event_route( + db: State<'_, Database>, + body: Ruma, + _room_id: String, + _event_id: String, + _txn_id: String, +) -> MatrixResult { + let user_id = body.user_id.as_ref().expect("user is authenticated"); + + if let Ok(event_id) = db.rooms.append_pdu( + body.room_id.clone(), + user_id.clone(), + EventType::RoomRedaction, + serde_json::to_value(redaction::RedactionEventContent { + reason: body.reason.clone(), + }).unwrap(), + None, + None, + Some(body.event_id.clone()), + &db.globals, + ) { + MatrixResult(Ok(redact_event::Response { event_id })) + } else { + MatrixResult(Err(Error { + kind: ErrorKind::Unknown, + message: "Failed to redact event.".to_owned(), + status_code: http::StatusCode::BAD_REQUEST, + })) + } +} + #[get("/_matrix/client/r0/directory/room/<_room_alias>", data = "")] pub fn get_alias_route( db: State<'_, Database>, @@ -1220,6 +1254,7 @@ pub fn join_room_by_id_route( serde_json::to_value(event).unwrap(), None, Some(user_id.to_string()), + None, &db.globals, ) .unwrap(); @@ -1285,6 +1320,7 @@ pub fn leave_room_route( json!({"membership": "leave"}), None, Some(user_id.to_string()), + None, &db.globals, ) .unwrap(); @@ -1328,6 +1364,7 @@ pub fn invite_user_route( serde_json::to_value(event).unwrap(), None, Some(user_id.to_string()), + None, &db.globals, ) .unwrap(); @@ -1414,7 +1451,7 @@ pub async fn get_public_rooms_filtered_route( .deserialize() .unwrap() .alias - }).map(|a| a.to_string()), + }), name: state.get(&(EventType::RoomName, "".to_owned())).map(|s| { serde_json::from_value::>( s.content.clone(), @@ -1565,6 +1602,7 @@ pub fn create_message_event_route( serde_json::from_str(body.json_body.unwrap().get()).unwrap(), Some(unsigned), None, + None, &db.globals, ) { MatrixResult(Ok(create_message_event::Response { event_id })) @@ -1598,6 +1636,7 @@ pub fn create_state_event_for_key_route( serde_json::from_str(body.json_body.clone().unwrap().get()).unwrap(), None, Some(body.state_key.clone()), + None, &db.globals, ) { MatrixResult(Ok(create_state_event_for_key::Response { event_id })) @@ -1630,6 +1669,7 @@ pub fn create_state_event_for_empty_key_route( serde_json::from_str(body.json_body.unwrap().get()).unwrap(), None, Some("".to_owned()), + None, &db.globals, ) { MatrixResult(Ok(create_state_event_for_empty_key::Response { event_id })) diff --git a/src/database/rooms.rs b/src/database/rooms.rs index 87f3429e..8e626cb0 100644 --- a/src/database/rooms.rs +++ b/src/database/rooms.rs @@ -12,7 +12,7 @@ use ruma_events::{ EventJson, EventType, }; use ruma_identifiers::{EventId, RoomId, UserId}; - +use sled::IVec; use std::{ collections::{BTreeMap, HashMap}, convert::{TryFrom, TryInto}, @@ -110,28 +110,50 @@ impl Rooms { self.eventid_pduid .get(event_id.to_string().as_bytes())? .map_or(Ok(None), |pdu_id| { - Ok(serde_json::from_slice( + Ok(Some(serde_json::from_slice( &self.pduid_pdu.get(pdu_id)?.ok_or(Error::BadDatabase( "eventid_pduid points to nonexistent pdu", ))?, - )?) - .map(Some) + )?)) }) } + /// Returns the pdu's id. + pub fn get_pdu_id(&self, event_id: &EventId) -> Result> { + self.eventid_pduid + .get(event_id.to_string().as_bytes())? + .map_or(Ok(None), |pdu_id| Ok(Some(pdu_id))) + } + /// Returns the pdu. pub fn get_pdu(&self, event_id: &EventId) -> Result> { self.eventid_pduid .get(event_id.to_string().as_bytes())? .map_or(Ok(None), |pdu_id| { - Ok(serde_json::from_slice( + Ok(Some(serde_json::from_slice( &self.pduid_pdu.get(pdu_id)?.ok_or(Error::BadDatabase( "eventid_pduid points to nonexistent pdu", ))?, - )?) - .map(Some) + )?)) }) } + /// Returns the pdu. + pub fn get_pdu_from_id(&self, pdu_id: &IVec) -> Result> { + self.pduid_pdu + .get(pdu_id)? + .map_or(Ok(None), |pdu| Ok(Some(serde_json::from_slice(&pdu)?))) + } + + /// Returns the pdu. + pub fn replace_pdu(&self, pdu_id: &IVec, pdu: &PduEvent) -> Result<()> { + if self.pduid_pdu.get(&pdu_id)?.is_some() { + self.pduid_pdu + .insert(&pdu_id, &*serde_json::to_string(pdu)?)?; + Ok(()) + } else { + Err(Error::BadRequest("pdu does not exist")) + } + } /// Returns the leaf pdus of a room. pub fn get_pdu_leaves(&self, room_id: &RoomId) -> Result> { @@ -177,6 +199,7 @@ impl Rooms { content: serde_json::Value, unsigned: Option>, state_key: Option, + redacts: Option, globals: &super::globals::Globals, ) -> Result { // TODO: Make sure this isn't called twice in parallel @@ -435,7 +458,7 @@ impl Rooms { .try_into() .expect("depth can overflow and should be deprecated..."), auth_events: Vec::new(), - redacts: None, + redacts, unsigned, hashes: ruma_federation_api::EventHash { sha256: "aaa".to_owned(), @@ -555,7 +578,21 @@ impl Rooms { .map(|(_, v)| Ok(serde_json::from_slice(&v)?)) } - /// Makes a user join a room. Only call this if the membership is Join already + /// Replace a PDU with the redacted form. + pub fn redact_pdu(&self, event_id: &EventId) -> Result<()> { + if let Some(pdu_id) = self.get_pdu_id(event_id)? { + let mut pdu = self + .get_pdu_from_id(&pdu_id)? + .ok_or(Error::BadDatabase("pduid points to invalid pdu"))?; + pdu.redact(); + self.replace_pdu(&pdu_id, &pdu)?; + Ok(()) + } else { + Err(Error::BadRequest("eventid does not exist")) + } + } + + /// Update current membership data. fn update_membership( &self, room_id: &RoomId, diff --git a/src/pdu.rs b/src/pdu.rs index 0e1b3de6..3e1ac0ac 100644 --- a/src/pdu.rs +++ b/src/pdu.rs @@ -33,6 +33,38 @@ pub struct PduEvent { } impl PduEvent { + pub fn redact(&mut self) { + self.unsigned.clear(); + let allowed = match self.kind { + EventType::RoomMember => vec!["membership"], + EventType::RoomCreate => vec!["creator"], + EventType::RoomJoinRules => vec!["join_rule"], + EventType::RoomPowerLevels => vec![ + "ban", + "events", + "events_default", + "kick", + "redact", + "state_default", + "users", + "users_default", + ], + EventType::RoomHistoryVisibility => vec!["history_visibility"], + _ => vec![], + }; + + let old_content = self.content.as_object_mut().unwrap(); // TODO error + let mut new_content = serde_json::Map::new(); + + for key in allowed { + if let Some(value) = old_content.remove(key) { + new_content.insert(key.to_owned(), value); + } + } + + self.content = new_content.into(); + } + pub fn to_room_event(&self) -> EventJson { // Can only fail in rare circumstances that won't ever happen here, see // https://docs.rs/serde_json/1.0.50/serde_json/fn.to_string.html @@ -40,7 +72,6 @@ impl PduEvent { // EventJson's deserialize implementation always returns `Ok(...)` serde_json::from_str::>(&json).unwrap() } - pub fn to_state_event(&self) -> EventJson { let json = serde_json::to_string(&self).unwrap(); serde_json::from_str::>(&json).unwrap() diff --git a/src/server_server.rs b/src/server_server.rs index 84ca5cc3..6aa1e99b 100644 --- a/src/server_server.rs +++ b/src/server_server.rs @@ -4,7 +4,9 @@ use log::error; use rocket::{get, response::content::Json, State}; use ruma_api::Endpoint; use ruma_client_api::error::Error; -use ruma_federation_api::{v1::get_server_version, v2::get_server_keys}; +use ruma_federation_api::discovery::{ + get_server_keys::v2 as get_server_keys, get_server_version::v1 as get_server_version, +}; use serde_json::json; use std::{ collections::BTreeMap, From 9c26e22ad7d1d821feba6253703c074bcb3c1bf6 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 24 May 2020 08:30:57 +0200 Subject: [PATCH 2/3] improvement: load aliases from database --- src/client_server.rs | 12 ++++++------ src/database/rooms.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/client_server.rs b/src/client_server.rs index 0701be1a..36cdb38b 100644 --- a/src/client_server.rs +++ b/src/client_server.rs @@ -1272,17 +1272,17 @@ pub fn join_room_by_id_or_alias_route( ) -> MatrixResult { let room_id = match RoomId::try_from(body.room_id_or_alias.clone()) { Ok(room_id) => room_id, - Err(room_alias) => { - if room_alias.server_name() == db.globals.server_name() { + Err(_) => { + if let Some(room_id) = db.rooms.id_from_alias(body.room_id_or_alias.as_ref()).unwrap() { + room_id + } else { + // Ask creator server of the room to join TODO ask someone else when not available + //server_server::send_request(data, destination, request) return MatrixResult(Err(Error { kind: ErrorKind::NotFound, message: "Room alias not found.".to_owned(), status_code: http::StatusCode::BAD_REQUEST, })); - } else { - // Ask creator server of the room to join TODO ask someone else when not available - //server_server::send_request(data, destination, request) - todo!(); } } }; diff --git a/src/database/rooms.rs b/src/database/rooms.rs index 8e626cb0..8969da11 100644 --- a/src/database/rooms.rs +++ b/src/database/rooms.rs @@ -26,6 +26,8 @@ pub struct Rooms { pub(super) roomid_pduleaves: sled::Tree, pub(super) roomstateid_pdu: sled::Tree, // RoomStateId = Room + StateType + StateKey + pub(super) alias_roomid: sled::Tree, + pub(super) userroomid_joined: sled::Tree, pub(super) roomuserid_joined: sled::Tree, pub(super) userroomid_invited: sled::Tree, @@ -646,6 +648,16 @@ impl Rooms { Ok(()) } + pub fn id_from_alias(&self, alias: &str) -> Result> { + if !alias.starts_with('#') { + return Err(Error::BadRequest("room alias does not start with #")); + } + + self.alias_roomid.get(alias)?.map_or(Ok(None), |bytes| { + Ok(Some(RoomId::try_from(utils::string_from_bytes(&bytes)?)?)) + }) + } + /// Returns an iterator over all rooms a user joined. pub fn room_members(&self, room_id: &RoomId) -> impl Iterator> { self.roomuserid_joined From 4e507ef70624fcaf3386bf3ee71c9bfb65801754 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Mon, 25 May 2020 23:24:13 +0200 Subject: [PATCH 3/3] feat: room visibility and aliases --- Cargo.lock | 109 +++++++------- Cargo.toml | 10 +- README.md | 2 +- Rocket-example.toml | 3 + src/client_server.rs | 321 ++++++++++++++++++++++++++++++++---------- src/database.rs | 4 + src/database/rooms.rs | 98 +++++++++---- src/database/users.rs | 5 +- src/main.rs | 5 + 9 files changed, 399 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc9840f7..6b41ec36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ checksum = "26c4f3195085c36ea8d24d32b2f828d23296a9370a28aa39d111f6f16bef9f3b" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -279,7 +279,7 @@ dependencies = [ "bitflags", "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -423,7 +423,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -557,9 +557,9 @@ checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] name = "hyper" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96816e1d921eca64d208a85aab4f7798455a8e34229ee5a88c935bdee1b78b14" +checksum = "a6e7655b9594024ad0ee439f3b5a7299369dc2a3f459b47c696f9ff676f9aa1f" dependencies = [ "bytes", "futures-channel", @@ -571,8 +571,8 @@ dependencies = [ "httparse", "itoa", "log", - "net2", "pin-project", + "socket2", "time", "tokio", "tower-service", @@ -663,9 +663,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7" +checksum = "ce10c23ad2ea25ceca0093bd3192229da4c5b3c0f2de499c1ecac0d98d452177" dependencies = [ "wasm-bindgen", ] @@ -697,9 +697,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" [[package]] name = "lock_api" @@ -1004,7 +1004,7 @@ checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -1195,9 +1195,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.13" +version = "0.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703516ae74571f24b465b4a1431e81e2ad51336cb0ded733a55a1aa3eccac196" +checksum = "06b3fefa4f12272808f809a0af618501fdaba41a58963c5fb72238ab0be09603" dependencies = [ "cc", "libc", @@ -1291,13 +1291,13 @@ checksum = "52b82b4567b9af9b40a86f7778821c016ea961f55e4fee255f8f24bb28ee7452" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] name = "ruma-client-api" version = "0.9.0" -source = "git+https://github.com/ruma/ruma-client-api.git#b064daf23dbf970933e83ce3b84a2563c5e646e7" +source = "git+https://github.com/ruma/ruma-client-api.git?rev=c725288cd099690c1d13f1a9b9e57228bc860a62#c725288cd099690c1d13f1a9b9e57228bc860a62" dependencies = [ "http", "js_int", @@ -1325,8 +1325,8 @@ dependencies = [ [[package]] name = "ruma-events" -version = "0.21.2" -source = "git+https://github.com/ruma/ruma-events.git#a17714669da1db4aa7bf10948463bb964cf5058a" +version = "0.21.3" +source = "git+https://github.com/ruma/ruma-events.git?rev=4d09416cd1663d63c22153705c9e1fd77910797f#4d09416cd1663d63c22153705c9e1fd77910797f" dependencies = [ "js_int", "ruma-common", @@ -1335,16 +1335,17 @@ dependencies = [ "ruma-serde", "serde", "serde_json", + "strum", ] [[package]] name = "ruma-events-macros" -version = "0.21.2" -source = "git+https://github.com/ruma/ruma-events.git#a17714669da1db4aa7bf10948463bb964cf5058a" +version = "0.21.3" +source = "git+https://github.com/ruma/ruma-events.git?rev=4d09416cd1663d63c22153705c9e1fd77910797f#4d09416cd1663d63c22153705c9e1fd77910797f" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -1491,22 +1492,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -1570,6 +1571,18 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" +[[package]] +name = "socket2" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi 0.3.8", +] + [[package]] name = "spin" version = "0.5.2" @@ -1600,7 +1613,7 @@ dependencies = [ "heck", "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -1616,9 +1629,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.25" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f14a640819f79b72a710c0be059dce779f9339ae046c8bef12c361d56702146f" +checksum = "bb37da98a55b1d08529362d9cbb863be17556873df2585904ab9d2bc951291d0" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", @@ -1656,7 +1669,7 @@ checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -1700,7 +1713,7 @@ checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", ] [[package]] @@ -1858,9 +1871,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" -version = "0.2.62" +version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551" +checksum = "4c2dc4aa152834bc334f506c1a06b866416a8b6697d5c9f75b9a689c8486def0" dependencies = [ "cfg-if", "serde", @@ -1870,24 +1883,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.62" +version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94" +checksum = "ded84f06e0ed21499f6184df0e0cb3494727b0c5da89534e0fcc55c51d812101" dependencies = [ "bumpalo", "lazy_static", "log", "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a369c5e1dfb7569e14d62af4da642a3cbc2f9a3652fe586e26ac22222aa4b04" +checksum = "64487204d863f109eb77e8462189d111f27cb5712cc9fdb3461297a76963a2f6" dependencies = [ "cfg-if", "js-sys", @@ -1897,9 +1910,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.62" +version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776" +checksum = "838e423688dac18d73e31edce74ddfac468e37b1506ad163ffaf0a46f703ffe3" dependencies = [ "quote 1.0.6", "wasm-bindgen-macro-support", @@ -1907,28 +1920,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.62" +version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a" +checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.6", - "syn 1.0.25", + "syn 1.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.62" +version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad" +checksum = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd" [[package]] name = "web-sys" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc359e5dd3b46cb9687a051d50a2fdd228e4ba7cf6fcf861a5365c3d671a642" +checksum = "7b72fe77fd39e4bd3eaa4412fd299a0be6b3dfe9d2597e2f1c20beb968f41d17" dependencies = [ "js-sys", "wasm-bindgen", @@ -1936,9 +1949,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f50e1972865d6b1adb54167d1c8ed48606004c2c9d0ea5f1eeb34d95e863ef" +checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" dependencies = [ "ring", "untrusted", diff --git a/Cargo.toml b/Cargo.toml index c864508e..198521e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,10 @@ edition = "2018" [dependencies] rocket = { git = "https://github.com/SergioBenitez/Rocket.git", branch = "async", features = ["tls"] } http = "0.2.1" -ruma-client-api = { git = "https://github.com/ruma/ruma-client-api.git" } +ruma-client-api = { git = "https://github.com/ruma/ruma-client-api.git", rev = "c725288cd099690c1d13f1a9b9e57228bc860a62" } ruma-identifiers = { version = "0.16.1", features = ["rand"] } ruma-api = "0.16.1" -ruma-events = { git = "https://github.com/ruma/ruma-events.git" } +ruma-events = { git = "https://github.com/ruma/ruma-events.git", rev = "4d09416cd1663d63c22153705c9e1fd77910797f" } ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git", rev = "1ca545cba8dfd43e0fc8e3c18e1311fb73390a97" } ruma-federation-api = { git = "https://github.com/ruma/ruma-federation-api.git", rev = "4cf4aa6ef74b25ad8c14d99d7774129f023df163" } log = "0.4.8" @@ -25,15 +25,15 @@ sled = "0.31.0" directories = "2.0.2" js_int = "0.1.5" serde_json = { version = "1.0.53", features = ["raw_value"] } -serde = "1.0.110" +serde = "1.0.111" tokio = { version = "0.2.21", features = ["macros"] } rand = "0.7.3" rust-argon2 = "0.8.2" -reqwest = "0.10.4" +reqwest = "=0.10.4" base64 = "0.12.1" thiserror = "1.0.19" ruma-common = "0.1.2" image = { version = "0.23.4", default-features = false, features = ["jpeg", "png", "gif"] } [patch.crates-io] -ruma-events = { git = "https://github.com/ruma/ruma-events.git" } +ruma-events = { git = "https://github.com/ruma/ruma-events.git", rev = "4d09416cd1663d63c22153705c9e1fd77910797f" } diff --git a/README.md b/README.md index 94061a87..772fb96c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Also check out the [milestones](https://git.koesters.xyz/timo/conduit/milestones #### How can I contribute? -If you want to help, you may be able to find something in the issue tracker. If you do, comment on the issue, so others know. You can also join #conduit:matrix.org and ask there. +If you want to help, you may be able to find something in the issue tracker. If you do, comment on the issue, so others know. You can also join #conduit:matrix.org and ask there. #### Donate diff --git a/Rocket-example.toml b/Rocket-example.toml index fb9f6d65..924b540e 100644 --- a/Rocket-example.toml +++ b/Rocket-example.toml @@ -3,6 +3,9 @@ server_name = "your.server.name" port = 8448 address = "0.0.0.0" +# Default path is in this user's data +#database_path = "/home/timo/MyConduitServer" + #[global.tls] #certs = "/etc/letsencrypt/live/your.server.name/fullchain.pem" #key = "/etc/letsencrypt/live/your.server.name/privkey.pem" diff --git a/src/client_server.rs b/src/client_server.rs index 36cdb38b..150555c7 100644 --- a/src/client_server.rs +++ b/src/client_server.rs @@ -5,15 +5,18 @@ use std::{ }; use log::{debug, warn}; -use rocket::{get, options, post, put, State}; +use rocket::{delete, get, options, post, put, State}; use ruma_client_api::{ error::{Error, ErrorKind}, r0::{ account::{get_username_availability, register}, - alias::get_alias, + alias::{create_alias, delete_alias, get_alias}, capabilities::get_capabilities, config::{get_global_account_data, set_global_account_data}, - directory::{self, get_public_rooms, get_public_rooms_filtered}, + directory::{ + self, get_public_rooms, get_public_rooms_filtered, get_room_visibility, + set_room_visibility, + }, filter::{self, create_filter, get_filter}, keys::{claim_keys, get_keys, upload_keys}, media::{create_content, get_content, get_content_thumbnail, get_media_config}, @@ -28,6 +31,7 @@ use ruma_client_api::{ }, push::{get_pushrules_all, set_pushrule, set_pushrule_enabled}, read_marker::set_read_marker, + redact::redact_event, room::{self, create_room}, session::{get_login_types, login, logout}, state::{ @@ -39,16 +43,16 @@ use ruma_client_api::{ to_device::{self, send_event_to_device}, typing::create_typing_event, uiaa::{AuthFlow, UiaaInfo, UiaaResponse}, - user_directory::search_users, redact::redact_event, + user_directory::search_users, }, unversioned::get_supported_versions, }; use ruma_events::{ collections::only::Event as EduEvent, - room::{guest_access, history_visibility, join_rules, member, redaction}, + room::{canonical_alias, guest_access, history_visibility, join_rules, member, redaction}, EventJson, EventType, }; -use ruma_identifiers::{RoomId, RoomVersionId, UserId}; +use ruma_identifiers::{RoomAliasId, RoomId, RoomVersionId, UserId}; use serde_json::{json, value::RawValue}; use crate::{server_server, utils, Database, MatrixResult, Ruma}; @@ -671,7 +675,7 @@ pub fn get_profile_route( MatrixResult(Err(Error { kind: ErrorKind::NotFound, message: "Profile was not found.".to_owned(), - status_code: http::StatusCode::BAD_REQUEST, + status_code: http::StatusCode::NOT_FOUND, })) } @@ -908,8 +912,32 @@ pub fn create_room_route( let room_id = RoomId::new(db.globals.server_name()).expect("host is valid"); let user_id = body.user_id.as_ref().expect("user is authenticated"); - // TODO: Create alias and check if it already exists + let alias = if let Some(localpart) = &body.room_alias_name { + // TODO: Check for invalid characters and maximum length + if let Ok(alias) = + RoomAliasId::try_from(format!("#{}:{}", localpart, db.globals.server_name())) + { + if db.rooms.id_from_alias(&alias).unwrap().is_some() { + return MatrixResult(Err(Error { + kind: ErrorKind::Unknown, + message: "Alias already exists.".to_owned(), + status_code: http::StatusCode::BAD_REQUEST, + })); + } + Some(alias) + } else { + return MatrixResult(Err(Error { + kind: ErrorKind::Unknown, + message: "Invalid alias.".to_owned(), + status_code: http::StatusCode::BAD_REQUEST, + })); + } + } else { + None + }; + + // 1. The room create event db.rooms .append_pdu( room_id.clone(), @@ -917,11 +945,11 @@ pub fn create_room_route( EventType::RoomCreate, serde_json::to_value(ruma_events::room::create::CreateEventContent { creator: user_id.clone(), - federate: body + federate: body.creation_content.as_ref().map_or(true, |c| c.federate), + predecessor: body .creation_content .as_ref() - .map_or(true, |c| c.federate), - predecessor: body.creation_content.as_ref().and_then(|c| c.predecessor.clone()), + .and_then(|c| c.predecessor.clone()), room_version: RoomVersionId::version_5(), }) .unwrap(), @@ -932,7 +960,7 @@ pub fn create_room_route( ) .unwrap(); - // Join room + // 2. Let the room creator join db.rooms .append_pdu( room_id.clone(), @@ -960,7 +988,7 @@ pub fn create_room_route( room::Visibility::Public => create_room::RoomPreset::PublicChat, }); - // 0. Power levels + // 3. Power levels let mut users = BTreeMap::new(); users.insert(user_id.clone(), 100.into()); for invite_user_id in &body.invite { @@ -972,8 +1000,18 @@ pub fn create_room_route( .expect("TODO: handle. we hope the client sends a valid power levels json") } else { serde_json::to_value(ruma_events::room::power_levels::PowerLevelsEventContent { + ban: 50.into(), + events: BTreeMap::new(), + events_default: 0.into(), + invite: 50.into(), + kick: 50.into(), + redact: 50.into(), + state_default: 50.into(), users, - ..Default::default() + users_default: 0.into(), + notifications: ruma_events::room::power_levels::NotificationPowerLevels { + room: 50.into(), + }, }) .unwrap() }; @@ -990,8 +1028,8 @@ pub fn create_room_route( ) .unwrap(); - // 1. Events set by preset - // 1.1 Join Rules + // 4. Events set by preset + // 4.1 Join Rules db.rooms .append_pdu( room_id.clone(), @@ -1016,7 +1054,7 @@ pub fn create_room_route( ) .unwrap(); - // 1.2 History Visibility + // 4.2 History Visibility db.rooms .append_pdu( room_id.clone(), @@ -1033,7 +1071,7 @@ pub fn create_room_route( ) .unwrap(); - // 1.3 Guest Access + // 4.3 Guest Access db.rooms .append_pdu( room_id.clone(), @@ -1058,7 +1096,7 @@ pub fn create_room_route( ) .unwrap(); - // 2. Events listed in initial_state + // 5. Events listed in initial_state for create_room::InitialStateEvent { event_type, state_key, @@ -1079,7 +1117,7 @@ pub fn create_room_route( .unwrap(); } - // 3. Events implied by name and topic + // 6. Events implied by name and topic if let Some(name) = &body.name { db.rooms .append_pdu( @@ -1116,7 +1154,7 @@ pub fn create_room_route( .unwrap(); } - // 4. Events implied by invite (and TODO: invite_3pid) + // 7. Events implied by invite (and TODO: invite_3pid) for user in &body.invite { db.rooms .append_pdu( @@ -1139,10 +1177,24 @@ pub fn create_room_route( .unwrap(); } + // Homeserver specific stuff + if let Some(alias) = alias { + db.rooms + .set_alias(&alias, Some(&room_id), &db.globals) + .unwrap(); + } + + if let Some(room::Visibility::Public) = body.visibility { + db.rooms.set_public(&room_id, true).unwrap(); + } + MatrixResult(Ok(create_room::Response { room_id })) } -#[put("/_matrix/client/r0/rooms/<_room_id>/redact/<_event_id>/<_txn_id>", data = "")] +#[put( + "/_matrix/client/r0/rooms/<_room_id>/redact/<_event_id>/<_txn_id>", + data = "" +)] pub fn redact_event_route( db: State<'_, Database>, body: Ruma, @@ -1158,7 +1210,8 @@ pub fn redact_event_route( EventType::RoomRedaction, serde_json::to_value(redaction::RedactionEventContent { reason: body.reason.clone(), - }).unwrap(), + }) + .unwrap(), None, None, Some(body.event_id.clone()), @@ -1174,35 +1227,63 @@ pub fn redact_event_route( } } +#[put("/_matrix/client/r0/directory/room/<_room_alias>", data = "")] +pub fn create_alias_route( + db: State<'_, Database>, + body: Ruma, + _room_alias: String, +) -> MatrixResult { + if db.rooms.id_from_alias(&body.room_alias).unwrap().is_some() { + return MatrixResult(Err(Error { + kind: ErrorKind::Unknown, + message: "Alias already exists".to_owned(), + status_code: http::StatusCode::BAD_REQUEST, + })); + } + + db.rooms + .set_alias(&body.room_alias, Some(&body.room_id), &db.globals) + .unwrap(); + + MatrixResult(Ok(create_alias::Response)) +} + +#[delete("/_matrix/client/r0/directory/room/<_room_alias>", data = "")] +pub fn delete_alias_route( + db: State<'_, Database>, + body: Ruma, + _room_alias: String, +) -> MatrixResult { + db.rooms + .set_alias(&body.room_alias, None, &db.globals) + .unwrap(); + + MatrixResult(Ok(delete_alias::Response)) +} + #[get("/_matrix/client/r0/directory/room/<_room_alias>", data = "")] pub fn get_alias_route( db: State<'_, Database>, body: Ruma, _room_alias: String, ) -> MatrixResult { - warn!("TODO: get_alias_route"); - let room_id = if body.room_alias.server_name() == db.globals.server_name() { - match body.room_alias.alias() { - "conduit" => "!lgOCCXQKtXOAPlAlG5:conduit.rs", - _ => { - debug!("Room alias not found."); - return MatrixResult(Err(Error { - kind: ErrorKind::NotFound, - message: "Room not found.".to_owned(), - status_code: http::StatusCode::BAD_REQUEST, - })); - } + if body.room_alias.server_name() == db.globals.server_name() { + if let Some(room_id) = db.rooms.id_from_alias(&body.room_alias).unwrap() { + MatrixResult(Ok(get_alias::Response { + room_id, + servers: vec![db.globals.server_name().to_owned()], + })) + } else { + debug!("Room alias not found."); + return MatrixResult(Err(Error { + kind: ErrorKind::NotFound, + message: "Room with alias not found.".to_owned(), + status_code: http::StatusCode::BAD_REQUEST, + })); } } else { todo!("ask remote server"); } - .try_into() - .unwrap(); - - MatrixResult(Ok(get_alias::Response { - room_id, - servers: vec!["conduit.rs".to_owned()], - })) } #[post("/_matrix/client/r0/rooms/<_room_id>/join", data = "")] @@ -1273,7 +1354,11 @@ pub fn join_room_by_id_or_alias_route( let room_id = match RoomId::try_from(body.room_id_or_alias.clone()) { Ok(room_id) => room_id, Err(_) => { - if let Some(room_id) = db.rooms.id_from_alias(body.room_id_or_alias.as_ref()).unwrap() { + if let Some(room_id) = db + .rooms + .id_from_alias(&body.room_id_or_alias.clone().try_into().unwrap()) + .unwrap() + { room_id } else { // Ask creator server of the room to join TODO ask someone else when not available @@ -1379,6 +1464,35 @@ pub fn invite_user_route( } } +#[put("/_matrix/client/r0/directory/list/room/<_room_id>", data = "")] +pub async fn set_room_visibility_route( + db: State<'_, Database>, + body: Ruma, + _room_id: String, +) -> MatrixResult { + match body.visibility { + room::Visibility::Public => db.rooms.set_public(&body.room_id, true).unwrap(), + room::Visibility::Private => db.rooms.set_public(&body.room_id, false).unwrap(), + } + + MatrixResult(Ok(set_room_visibility::Response)) +} + +#[get("/_matrix/client/r0/directory/list/room/<_room_id>", data = "")] +pub async fn get_room_visibility_route( + db: State<'_, Database>, + body: Ruma, + _room_id: String, +) -> MatrixResult { + MatrixResult(Ok(get_room_visibility::Response { + visibility: if db.rooms.is_public_room(&body.room_id).unwrap() { + room::Visibility::Public + } else { + room::Visibility::Private + }, + })) +} + #[get("/_matrix/client/r0/publicRooms", data = "")] pub async fn get_public_rooms_route( db: State<'_, Database>, @@ -1436,9 +1550,10 @@ pub async fn get_public_rooms_filtered_route( ) -> MatrixResult { let mut chunk = db .rooms - .all_rooms() - .into_iter() + .public_rooms() .map(|room_id| { + let room_id = room_id.unwrap(); + let state = db.rooms.room_state(&room_id).unwrap(); directory::PublicRoomsChunk { @@ -1628,12 +1743,46 @@ pub fn create_state_event_for_key_route( ) -> MatrixResult { let user_id = body.user_id.as_ref().expect("user is authenticated"); - // Reponse of with/without key is the same + let content = + serde_json::from_str::(body.json_body.clone().unwrap().get()).unwrap(); + + if body.event_type == EventType::RoomCanonicalAlias { + let canonical_alias = serde_json::from_value::< + EventJson, + >(content.clone()) + .unwrap() + .deserialize() + .unwrap(); + + let mut aliases = canonical_alias.alt_aliases; + + if let Some(alias) = canonical_alias.alias { + aliases.push(alias); + } + + for alias in aliases { + if alias.server_name() != db.globals.server_name() + || db + .rooms + .id_from_alias(&alias) + .unwrap() + .filter(|room| room == &body.room_id) // Make sure it's the right room + .is_none() + { + return MatrixResult(Err(Error { + kind: ErrorKind::Unknown, + message: "You are only allowed to send canonical_alias events when it's aliases already exists".to_owned(), + status_code: http::StatusCode::BAD_REQUEST, + })); + } + } + } + if let Ok(event_id) = db.rooms.append_pdu( body.room_id.clone(), user_id.clone(), body.event_type.clone(), - serde_json::from_str(body.json_body.clone().unwrap().get()).unwrap(), + content, None, Some(body.state_key.clone()), None, @@ -1659,27 +1808,43 @@ pub fn create_state_event_for_empty_key_route( _room_id: String, _event_type: String, ) -> MatrixResult { - let user_id = body.user_id.as_ref().expect("user is authenticated"); + // This just calls create_state_event_for_key_route + let Ruma { + body: + create_state_event_for_empty_key::Request { + room_id, + event_type, + data, + }, + user_id, + device_id, + json_body, + } = body; - // Reponse of with/without key is the same - if let Ok(event_id) = db.rooms.append_pdu( - body.room_id.clone(), - user_id.clone(), - body.event_type.clone(), - serde_json::from_str(body.json_body.unwrap().get()).unwrap(), - None, - Some("".to_owned()), - None, - &db.globals, - ) { - MatrixResult(Ok(create_state_event_for_empty_key::Response { event_id })) - } else { - MatrixResult(Err(Error { - kind: ErrorKind::Unknown, - message: "Failed to send event.".to_owned(), - status_code: http::StatusCode::BAD_REQUEST, - })) - } + let response = create_state_event_for_key_route( + db, + Ruma { + body: create_state_event_for_key::Request { + room_id, + event_type, + data, + state_key: "".to_owned(), + }, + user_id, + device_id, + json_body, + }, + _room_id, + _event_type, + "".to_owned(), + ); + + MatrixResult(match response.0 { + Ok(create_state_event_for_key::Response { event_id }) => { + Ok(create_state_event_for_empty_key::Response { event_id }) + } + Err(e) => Err(e), + }) } #[get("/_matrix/client/r0/rooms/<_room_id>/state", data = "")] @@ -1973,17 +2138,19 @@ pub fn sync_route( let mut invited_rooms = BTreeMap::new(); for room_id in db.rooms.rooms_invited(&user_id) { let room_id = room_id.unwrap(); - let events = db - .rooms - .pdus_since(&room_id, since) - .unwrap() - .map(|pdu| pdu.unwrap().to_stripped_state_event()) - .collect(); invited_rooms.insert( - room_id, + room_id.clone(), sync_events::InvitedRoom { - invite_state: sync_events::InviteState { events }, + invite_state: sync_events::InviteState { + events: db + .rooms + .room_state(&room_id) + .unwrap() + .into_iter() + .map(|(_, pdu)| pdu.to_stripped_state_event()) + .collect(), + }, }, ); } @@ -2086,12 +2253,12 @@ pub fn get_message_events_route( .map(|pdu| pdu.to_room_event()) .collect::>(); - MatrixResult(Ok(get_message_events::Response { + MatrixResult(Ok(dbg!(get_message_events::Response { start: Some(body.from.clone()), end: prev_batch, chunk: room_events, state: Vec::new(), - })) + }))) } else { MatrixResult(Err(Error { kind: ErrorKind::Unknown, diff --git a/src/database.rs b/src/database.rs index 9c08a22e..de14805b 100644 --- a/src/database.rs +++ b/src/database.rs @@ -77,6 +77,10 @@ impl Database { roomid_pduleaves: db.open_tree("roomid_pduleaves").unwrap(), roomstateid_pdu: db.open_tree("roomstateid_pdu").unwrap(), + alias_roomid: db.open_tree("alias_roomid").unwrap(), + aliasid_alias: db.open_tree("alias_roomid").unwrap(), + publicroomids: db.open_tree("publicroomids").unwrap(), + userroomid_joined: db.open_tree("userroomid_joined").unwrap(), roomuserid_joined: db.open_tree("roomuserid_joined").unwrap(), userroomid_invited: db.open_tree("userroomid_invited").unwrap(), diff --git a/src/database/rooms.rs b/src/database/rooms.rs index 8969da11..1c25c259 100644 --- a/src/database/rooms.rs +++ b/src/database/rooms.rs @@ -11,7 +11,7 @@ use ruma_events::{ }, EventJson, EventType, }; -use ruma_identifiers::{EventId, RoomId, UserId}; +use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId}; use sled::IVec; use std::{ collections::{BTreeMap, HashMap}, @@ -27,6 +27,8 @@ pub struct Rooms { pub(super) roomstateid_pdu: sled::Tree, // RoomStateId = Room + StateType + StateKey pub(super) alias_roomid: sled::Tree, + pub(super) aliasid_alias: sled::Tree, // AliasId = RoomId + Count + pub(super) publicroomids: sled::Tree, pub(super) userroomid_joined: sled::Tree, pub(super) roomuserid_joined: sled::Tree, @@ -312,7 +314,7 @@ impl Rooms { .join_rule }); - if target_membership == member::MembershipState::Join { + let authorized = if target_membership == member::MembershipState::Join { let mut prev_events = prev_events.iter(); let prev_event = self .get_pdu(prev_events.next().ok_or(Error::BadRequest( @@ -392,34 +394,30 @@ impl Rooms { } } else { false + }; + + if authorized { + // Update our membership info + self.update_membership(&room_id, &target_user_id, &target_membership)?; } + + authorized } EventType::RoomCreate => prev_events.is_empty(), - _ if sender_membership == member::MembershipState::Join => { + + // Not allow any of the following events if the sender is not joined. + _ if sender_membership != member::MembershipState::Join => false, + + _ => { // TODO sender_power.unwrap_or(&power_levels.users_default) >= &power_levels.state_default } - - _ => false, } { error!("Unauthorized"); // Not authorized return Err(Error::BadRequest("event not authorized")); } - if event_type == EventType::RoomMember { - // TODO: Don't get this twice - let target_user_id = UserId::try_from(&**state_key)?; - self.update_membership( - &room_id, - &target_user_id, - &serde_json::from_value::>( - content.clone(), - )? - .deserialize()? - .membership, - )?; - } } } else if !self.is_joined(&sender, &room_id)? { return Err(Error::BadRequest("event not authorized")); @@ -648,14 +646,66 @@ impl Rooms { Ok(()) } - pub fn id_from_alias(&self, alias: &str) -> Result> { - if !alias.starts_with('#') { - return Err(Error::BadRequest("room alias does not start with #")); + pub fn set_alias( + &self, + alias: &RoomAliasId, + room_id: Option<&RoomId>, + globals: &super::globals::Globals, + ) -> Result<()> { + if let Some(room_id) = room_id { + self.alias_roomid + .insert(alias.alias(), &*room_id.to_string())?; + let mut aliasid = room_id.to_string().as_bytes().to_vec(); + aliasid.extend_from_slice(&globals.next_count()?.to_be_bytes()); + self.aliasid_alias.insert(aliasid, &*alias.alias())?; + } else { + if let Some(room_id) = self.alias_roomid.remove(alias.alias())? { + for key in self.aliasid_alias.scan_prefix(room_id).keys() { + self.aliasid_alias.remove(key?)?; + } + } + } + + Ok(()) + } + + pub fn id_from_alias(&self, alias: &RoomAliasId) -> Result> { + self.alias_roomid + .get(alias.alias())? + .map_or(Ok(None), |bytes| { + Ok(Some(RoomId::try_from(utils::string_from_bytes(&bytes)?)?)) + }) + } + + pub fn room_aliases(&self, room_id: &RoomId) -> impl Iterator> { + let mut prefix = room_id.to_string().as_bytes().to_vec(); + prefix.push(0xff); + + self.aliasid_alias + .scan_prefix(prefix) + .values() + .map(|bytes| Ok(RoomAliasId::try_from(utils::string_from_bytes(&bytes?)?)?)) + } + + pub fn set_public(&self, room_id: &RoomId, public: bool) -> Result<()> { + if public { + self.publicroomids.insert(room_id.to_string(), &[])?; + } else { + self.publicroomids.remove(room_id.to_string())?; } - self.alias_roomid.get(alias)?.map_or(Ok(None), |bytes| { - Ok(Some(RoomId::try_from(utils::string_from_bytes(&bytes)?)?)) - }) + Ok(()) + } + + pub fn is_public_room(&self, room_id: &RoomId) -> Result { + Ok(self.publicroomids.contains_key(room_id.to_string())?) + } + + pub fn public_rooms(&self) -> impl Iterator> { + self.publicroomids + .iter() + .keys() + .map(|bytes| Ok(RoomId::try_from(utils::string_from_bytes(&bytes?)?)?)) } /// Returns an iterator over all rooms a user joined. diff --git a/src/database/users.rs b/src/database/users.rs index 81a7bb8a..6540a70a 100644 --- a/src/database/users.rs +++ b/src/database/users.rs @@ -141,9 +141,8 @@ impl Users { let mut prefix = userdeviceid.clone(); prefix.push(0xff); - for result in self.todeviceid_events.scan_prefix(&prefix) { - let (key, value) = result?; - self.todeviceid_events.remove(key)?; + for key in self.todeviceid_events.scan_prefix(&prefix).keys() { + self.todeviceid_events.remove(key?)?; } // TODO: Remove onetimekeys diff --git a/src/main.rs b/src/main.rs index 3e34ded3..41462824 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,12 +50,17 @@ fn setup_rocket() -> rocket::Rocket { client_server::set_read_marker_route, client_server::create_typing_event_route, client_server::create_room_route, + client_server::redact_event_route, + client_server::create_alias_route, + client_server::delete_alias_route, client_server::get_alias_route, client_server::join_room_by_id_route, client_server::join_room_by_id_or_alias_route, client_server::leave_room_route, client_server::forget_room_route, client_server::invite_user_route, + client_server::set_room_visibility_route, + client_server::get_room_visibility_route, client_server::get_public_rooms_route, client_server::get_public_rooms_filtered_route, client_server::search_users_route,