Merge pull request 'Small fixes' (#98) from fix into master
This commit is contained in:
		
						commit
						c655870d23
					
				
					 10 changed files with 353 additions and 408 deletions
				
			
		
							
								
								
									
										92
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										92
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -26,13 +26,13 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" | |||
| 
 | ||||
| [[package]] | ||||
| name = "async-trait" | ||||
| version = "0.1.31" | ||||
| version = "0.1.32" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "26c4f3195085c36ea8d24d32b2f828d23296a9370a28aa39d111f6f16bef9f3b" | ||||
| checksum = "0eb7f9ad01405feb3c1dac82463038945cf88eea4569acaf3ad662233496dd96" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -98,9 +98,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "bumpalo" | ||||
| version = "3.3.0" | ||||
| version = "3.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5356f1d23ee24a1f785a56d1d1a5f0fd5b0f6a0c0fb2412ce11da71649ab78f6" | ||||
| checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bytemuck" | ||||
|  | @ -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.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[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.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -621,9 +621,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "indexmap" | ||||
| version = "1.3.2" | ||||
| version = "1.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" | ||||
| checksum = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe" | ||||
| dependencies = [ | ||||
|  "autocfg", | ||||
| ] | ||||
|  | @ -1002,16 +1002,16 @@ version = "0.4.17" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pin-project-lite" | ||||
| version = "0.1.5" | ||||
| version = "0.1.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f7505eeebd78492e0f6108f7171c4948dbb120ee8119d9d77d0afa5469bef67f" | ||||
| checksum = "9df32da11d84f3a7d70205549562966279adb900e080fad3dccd8e64afccf0ad" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pin-utils" | ||||
|  | @ -1027,9 +1027,9 @@ checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" | |||
| 
 | ||||
| [[package]] | ||||
| name = "png" | ||||
| version = "0.16.3" | ||||
| version = "0.16.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2c68a431ed29933a4eb5709aca9800989758c97759345860fa5db3cfced0b65d" | ||||
| checksum = "12faa637ed9ae3d3c881332e54b5ae2dba81cda9fc4bbce0faa1ba53abcead50" | ||||
| dependencies = [ | ||||
|  "bitflags", | ||||
|  "crc32fast", | ||||
|  | @ -1066,9 +1066,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "proc-macro2" | ||||
| version = "1.0.17" | ||||
| version = "1.0.18" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" | ||||
| checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" | ||||
| 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.17", | ||||
|  "proc-macro2 1.0.18", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1289,9 +1289,9 @@ version = "0.16.1" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "52b82b4567b9af9b40a86f7778821c016ea961f55e4fee255f8f24bb28ee7452" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1343,9 +1343,9 @@ name = "ruma-events-macros" | |||
| version = "0.21.3" | ||||
| source = "git+https://github.com/ruma/ruma-events.git?rev=4d09416cd1663d63c22153705c9e1fd77910797f#4d09416cd1663d63c22153705c9e1fd77910797f" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1365,9 +1365,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "ruma-identifiers" | ||||
| version = "0.16.1" | ||||
| version = "0.16.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "77c93b9d5f951a2fb57b19c048a05ac1dbdb280ff7617ec6b02f54bf14318ed8" | ||||
| checksum = "6316cb248e3e0323a5a269b8eaed571404fb4f65c81848549e9ba99fd9b8e9de" | ||||
| dependencies = [ | ||||
|  "rand", | ||||
|  "serde", | ||||
|  | @ -1437,9 +1437,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "ryu" | ||||
| version = "1.0.4" | ||||
| version = "1.0.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" | ||||
| checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "schannel" | ||||
|  | @ -1505,9 +1505,9 @@ version = "1.0.111" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1611,9 +1611,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" | ||||
| dependencies = [ | ||||
|  "heck", | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1629,11 +1629,11 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "syn" | ||||
| version = "1.0.29" | ||||
| version = "1.0.30" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bb37da98a55b1d08529362d9cbb863be17556873df2585904ab9d2bc951291d0" | ||||
| checksum = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "unicode-xid 0.2.0", | ||||
| ] | ||||
|  | @ -1667,9 +1667,9 @@ version = "1.0.19" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1711,9 +1711,9 @@ version = "0.2.5" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1837,9 +1837,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "vcpkg" | ||||
| version = "0.2.8" | ||||
| version = "0.2.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" | ||||
| checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "version_check" | ||||
|  | @ -1890,9 +1890,9 @@ dependencies = [ | |||
|  "bumpalo", | ||||
|  "lazy_static", | ||||
|  "log", | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
| 
 | ||||
|  | @ -1924,9 +1924,9 @@ version = "0.2.63" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.17", | ||||
|  "proc-macro2 1.0.18", | ||||
|  "quote 1.0.6", | ||||
|  "syn 1.0.29", | ||||
|  "syn 1.0.30", | ||||
|  "wasm-bindgen-backend", | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ edition = "2018" | |||
| 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", rev = "c725288cd099690c1d13f1a9b9e57228bc860a62" } | ||||
| ruma-identifiers = { version = "0.16.1", features = ["rand"] } | ||||
| ruma-identifiers = { version = "0.16.2", features = ["rand"] } | ||||
| ruma-api = "0.16.1" | ||||
| ruma-events = { git = "https://github.com/ruma/ruma-events.git", rev = "4d09416cd1663d63c22153705c9e1fd77910797f" } | ||||
| ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git", rev = "1ca545cba8dfd43e0fc8e3c18e1311fb73390a97" } | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ use std::{ | |||
|     time::{Duration, SystemTime}, | ||||
| }; | ||||
| 
 | ||||
| use crate::{utils, Database, MatrixResult, Ruma}; | ||||
| use log::{debug, warn}; | ||||
| use rocket::{delete, get, options, post, put, State}; | ||||
| use ruma_client_api::{ | ||||
|  | @ -13,15 +14,13 @@ use ruma_client_api::{ | |||
|         alias::{create_alias, delete_alias, get_alias}, | ||||
|         capabilities::get_capabilities, | ||||
|         config::{get_global_account_data, set_global_account_data}, | ||||
|         device::{ | ||||
|             self, delete_device, delete_devices, get_device, get_devices, update_device, | ||||
|         }, | ||||
|         device::{self, delete_device, delete_devices, get_device, get_devices, update_device}, | ||||
|         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}, | ||||
|         keys::{self, claim_keys, get_keys, upload_keys}, | ||||
|         media::{create_content, get_content, get_content_thumbnail, get_media_config}, | ||||
|         membership::{ | ||||
|             forget_room, get_member_events, invite_user, join_room_by_id, join_room_by_id_or_alias, | ||||
|  | @ -58,8 +57,6 @@ use ruma_events::{ | |||
| use ruma_identifiers::{DeviceId, RoomAliasId, RoomId, RoomVersionId, UserId}; | ||||
| use serde_json::{json, value::RawValue}; | ||||
| 
 | ||||
| use crate::{server_server, utils, Database, MatrixResult, Ruma}; | ||||
| 
 | ||||
| const GUEST_NAME_LENGTH: usize = 10; | ||||
| const DEVICE_ID_LENGTH: usize = 10; | ||||
| const SESSION_ID_LENGTH: usize = 256; | ||||
|  | @ -176,7 +173,8 @@ pub fn register_route( | |||
| 
 | ||||
|     // Generate new device id if the user didn't specify one
 | ||||
|     let device_id = body | ||||
|         .device_id.clone() | ||||
|         .device_id | ||||
|         .clone() | ||||
|         .unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH)); | ||||
| 
 | ||||
|     // Generate new token for the device
 | ||||
|  | @ -184,7 +182,12 @@ pub fn register_route( | |||
| 
 | ||||
|     // Add device
 | ||||
|     db.users | ||||
|         .create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone()) | ||||
|         .create_device( | ||||
|             &user_id, | ||||
|             &device_id, | ||||
|             &token, | ||||
|             body.initial_device_display_name.clone(), | ||||
|         ) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     // Initial data
 | ||||
|  | @ -311,7 +314,12 @@ pub fn login_route( | |||
| 
 | ||||
|     // Add device
 | ||||
|     db.users | ||||
|         .create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone()) | ||||
|         .create_device( | ||||
|             &user_id, | ||||
|             &device_id, | ||||
|             &token, | ||||
|             body.initial_device_display_name.clone(), | ||||
|         ) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     MatrixResult(Ok(login::Response { | ||||
|  | @ -338,14 +346,23 @@ pub fn logout_route( | |||
| 
 | ||||
| #[get("/_matrix/client/r0/capabilities")] | ||||
| pub fn get_capabilities_route() -> MatrixResult<get_capabilities::Response> { | ||||
|     // TODO
 | ||||
|     //let mut available = BTreeMap::new();
 | ||||
|     //available.insert("5".to_owned(), get_capabilities::RoomVersionStability::Unstable);
 | ||||
|     let mut available = BTreeMap::new(); | ||||
|     available.insert( | ||||
|         "5".to_owned(), | ||||
|         get_capabilities::RoomVersionStability::Stable, | ||||
|     ); | ||||
|     available.insert( | ||||
|         "6".to_owned(), | ||||
|         get_capabilities::RoomVersionStability::Stable, | ||||
|     ); | ||||
| 
 | ||||
|     MatrixResult(Ok(get_capabilities::Response { | ||||
|         capabilities: get_capabilities::Capabilities { | ||||
|             change_password: None, | ||||
|             room_versions: None, //Some(get_capabilities::RoomVersionsCapability { default: "5".to_owned(), available }),
 | ||||
|             change_password: None, // None means it is possible
 | ||||
|             room_versions: Some(get_capabilities::RoomVersionsCapability { | ||||
|                 default: "6".to_owned(), | ||||
|                 available, | ||||
|             }), | ||||
|             custom_capabilities: BTreeMap::new(), | ||||
|         }, | ||||
|     })) | ||||
|  | @ -749,11 +766,21 @@ pub fn get_keys_route( | |||
|     for (user_id, device_ids) in &body.device_keys { | ||||
|         if device_ids.is_empty() { | ||||
|             let mut container = BTreeMap::new(); | ||||
|             for (device_id, keys) in db | ||||
|             for (device_id, mut keys) in db | ||||
|                 .users | ||||
|                 .all_device_keys(&user_id.clone()) | ||||
|                 .map(|r| r.unwrap()) | ||||
|             { | ||||
|                 let metadata = db | ||||
|                     .users | ||||
|                     .get_device_metadata(user_id, &device_id) | ||||
|                     .unwrap() | ||||
|                     .expect("this device should exist"); | ||||
| 
 | ||||
|                 keys.unsigned = Some(keys::UnsignedDeviceInfo { | ||||
|                     device_display_name: metadata.display_name, | ||||
|                 }); | ||||
| 
 | ||||
|                 container.insert(device_id, keys); | ||||
|             } | ||||
|             device_keys.insert(user_id.clone(), container); | ||||
|  | @ -761,7 +788,18 @@ pub fn get_keys_route( | |||
|             for device_id in device_ids { | ||||
|                 let mut container = BTreeMap::new(); | ||||
|                 for keys in db.users.get_device_keys(&user_id.clone(), &device_id) { | ||||
|                     container.insert(device_id.clone(), keys.unwrap()); | ||||
|                     let mut keys = keys.unwrap(); | ||||
|                     let metadata = db | ||||
|                         .users | ||||
|                         .get_device_metadata(user_id, &device_id) | ||||
|                         .unwrap() | ||||
|                         .expect("this device should exist"); | ||||
| 
 | ||||
|                     keys.unsigned = Some(keys::UnsignedDeviceInfo { | ||||
|                         device_display_name: metadata.display_name, | ||||
|                     }); | ||||
| 
 | ||||
|                     container.insert(device_id.clone(), keys); | ||||
|                 } | ||||
|                 device_keys.insert(user_id.clone(), container); | ||||
|             } | ||||
|  | @ -883,18 +921,12 @@ pub fn create_typing_event_route( | |||
|     _user_id: String, | ||||
| ) -> MatrixResult<create_typing_event::Response> { | ||||
|     let user_id = body.user_id.as_ref().expect("user is authenticated"); | ||||
|     let edu = EduEvent::Typing(ruma_events::typing::TypingEvent { | ||||
|         content: ruma_events::typing::TypingEventContent { | ||||
|             user_ids: vec![user_id.clone()], | ||||
|         }, | ||||
|         room_id: None, // None because it can be inferred
 | ||||
|     }); | ||||
| 
 | ||||
|     if body.typing { | ||||
|         db.rooms | ||||
|             .edus | ||||
|             .roomactive_add( | ||||
|                 edu, | ||||
|                 &user_id, | ||||
|                 &body.room_id, | ||||
|                 body.timeout.map(|d| d.as_millis() as u64).unwrap_or(30000) | ||||
|                     + utils::millis_since_unix_epoch().try_into().unwrap_or(0), | ||||
|  | @ -902,7 +934,10 @@ pub fn create_typing_event_route( | |||
|             ) | ||||
|             .unwrap(); | ||||
|     } else { | ||||
|         db.rooms.edus.roomactive_remove(edu, &body.room_id).unwrap(); | ||||
|         db.rooms | ||||
|             .edus | ||||
|             .roomactive_remove(&user_id, &body.room_id, &db.globals) | ||||
|             .unwrap(); | ||||
|     } | ||||
| 
 | ||||
|     MatrixResult(Ok(create_typing_event::Response)) | ||||
|  | @ -954,7 +989,7 @@ pub fn create_room_route( | |||
|                     .creation_content | ||||
|                     .as_ref() | ||||
|                     .and_then(|c| c.predecessor.clone()), | ||||
|                 room_version: RoomVersionId::version_5(), | ||||
|                 room_version: RoomVersionId::version_6(), | ||||
|             }) | ||||
|             .unwrap(), | ||||
|             None, | ||||
|  | @ -1279,11 +1314,11 @@ pub fn get_alias_route( | |||
|             })) | ||||
|         } else { | ||||
|             debug!("Room alias not found."); | ||||
|             return MatrixResult(Err(Error { | ||||
|             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"); | ||||
|  | @ -1859,23 +1894,23 @@ pub fn get_state_events_route( | |||
| ) -> MatrixResult<get_state_events::Response> { | ||||
|     let user_id = body.user_id.as_ref().expect("user is authenticated"); | ||||
| 
 | ||||
|     if db.rooms.is_joined(user_id, &body.room_id).unwrap() { | ||||
|         MatrixResult(Ok(get_state_events::Response { | ||||
|             room_state: db | ||||
|                 .rooms | ||||
|                 .room_state(&body.room_id) | ||||
|                 .unwrap() | ||||
|                 .values() | ||||
|                 .map(|pdu| pdu.to_state_event()) | ||||
|                 .collect(), | ||||
|         })) | ||||
|     } else { | ||||
|         MatrixResult(Err(Error { | ||||
|     if !db.rooms.is_joined(user_id, &body.room_id).unwrap() { | ||||
|         return MatrixResult(Err(Error { | ||||
|             kind: ErrorKind::Forbidden, | ||||
|             message: "You don't have permission to view the room state.".to_owned(), | ||||
|             status_code: http::StatusCode::BAD_REQUEST, | ||||
|         })) | ||||
|             status_code: http::StatusCode::FORBIDDEN, | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     MatrixResult(Ok(get_state_events::Response { | ||||
|         room_state: db | ||||
|             .rooms | ||||
|             .room_state(&body.room_id) | ||||
|             .unwrap() | ||||
|             .values() | ||||
|             .map(|pdu| pdu.to_state_event()) | ||||
|             .collect(), | ||||
|     })) | ||||
| } | ||||
| 
 | ||||
| #[get(
 | ||||
|  | @ -1891,28 +1926,28 @@ pub fn get_state_events_for_key_route( | |||
| ) -> MatrixResult<get_state_events_for_key::Response> { | ||||
|     let user_id = body.user_id.as_ref().expect("user is authenticated"); | ||||
| 
 | ||||
|     if db.rooms.is_joined(user_id, &body.room_id).unwrap() { | ||||
|         if let Some(event) = db | ||||
|             .rooms | ||||
|             .room_state(&body.room_id) | ||||
|             .unwrap() | ||||
|             .get(&(body.event_type.clone(), body.state_key.clone())) | ||||
|         { | ||||
|             MatrixResult(Ok(get_state_events_for_key::Response { | ||||
|                 content: serde_json::value::to_raw_value(&event.content).unwrap(), | ||||
|             })) | ||||
|         } else { | ||||
|             MatrixResult(Err(Error { | ||||
|                 kind: ErrorKind::NotFound, | ||||
|                 message: "State event not found.".to_owned(), | ||||
|                 status_code: http::StatusCode::BAD_REQUEST, | ||||
|             })) | ||||
|         } | ||||
|     } else { | ||||
|         MatrixResult(Err(Error { | ||||
|     if !db.rooms.is_joined(user_id, &body.room_id).unwrap() { | ||||
|         return MatrixResult(Err(Error { | ||||
|             kind: ErrorKind::Forbidden, | ||||
|             message: "You don't have permission to view the room state.".to_owned(), | ||||
|             status_code: http::StatusCode::BAD_REQUEST, | ||||
|             status_code: http::StatusCode::FORBIDDEN, | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     if let Some(event) = db | ||||
|         .rooms | ||||
|         .room_state(&body.room_id) | ||||
|         .unwrap() | ||||
|         .get(&(body.event_type.clone(), body.state_key.clone())) | ||||
|     { | ||||
|         MatrixResult(Ok(get_state_events_for_key::Response { | ||||
|             content: serde_json::value::to_raw_value(&event.content).unwrap(), | ||||
|         })) | ||||
|     } else { | ||||
|         MatrixResult(Err(Error { | ||||
|             kind: ErrorKind::NotFound, | ||||
|             message: "State event not found.".to_owned(), | ||||
|             status_code: http::StatusCode::NOT_FOUND, | ||||
|         })) | ||||
|     } | ||||
| } | ||||
|  | @ -1929,27 +1964,27 @@ pub fn get_state_events_for_empty_key_route( | |||
| ) -> MatrixResult<get_state_events_for_key::Response> { | ||||
|     let user_id = body.user_id.as_ref().expect("user is authenticated"); | ||||
| 
 | ||||
|     if db.rooms.is_joined(user_id, &body.room_id).unwrap() { | ||||
|         if let Some(event) = db | ||||
|             .rooms | ||||
|             .room_state(&body.room_id) | ||||
|             .unwrap() | ||||
|             .get(&(body.event_type.clone(), "".to_owned())) | ||||
|         { | ||||
|             MatrixResult(Ok(get_state_events_for_key::Response { | ||||
|                 content: serde_json::value::to_raw_value(event).unwrap(), | ||||
|             })) | ||||
|         } else { | ||||
|             MatrixResult(Err(Error { | ||||
|                 kind: ErrorKind::NotFound, | ||||
|                 message: "State event not found.".to_owned(), | ||||
|                 status_code: http::StatusCode::BAD_REQUEST, | ||||
|             })) | ||||
|         } | ||||
|     } else { | ||||
|         MatrixResult(Err(Error { | ||||
|     if !db.rooms.is_joined(user_id, &body.room_id).unwrap() { | ||||
|         return MatrixResult(Err(Error { | ||||
|             kind: ErrorKind::Forbidden, | ||||
|             message: "You don't have permission to view the room state.".to_owned(), | ||||
|             status_code: http::StatusCode::FORBIDDEN, | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     if let Some(event) = db | ||||
|         .rooms | ||||
|         .room_state(&body.room_id) | ||||
|         .unwrap() | ||||
|         .get(&(body.event_type.clone(), "".to_owned())) | ||||
|     { | ||||
|         MatrixResult(Ok(get_state_events_for_key::Response { | ||||
|             content: serde_json::value::to_raw_value(event).unwrap(), | ||||
|         })) | ||||
|     } else { | ||||
|         MatrixResult(Err(Error { | ||||
|             kind: ErrorKind::NotFound, | ||||
|             message: "State event not found.".to_owned(), | ||||
|             status_code: http::StatusCode::BAD_REQUEST, | ||||
|         })) | ||||
|     } | ||||
|  | @ -2011,7 +2046,12 @@ pub fn sync_route( | |||
|                     (db.rooms | ||||
|                         .pdus_since(&room_id, last_read) | ||||
|                         .unwrap() | ||||
|                         .filter(|pdu| matches!(pdu.as_ref().unwrap().kind.clone(), EventType::RoomMessage | EventType::RoomEncrypted)) | ||||
|                         .filter(|pdu| { | ||||
|                             matches!( | ||||
|                                 pdu.as_ref().unwrap().kind.clone(), | ||||
|                                 EventType::RoomMessage | EventType::RoomEncrypted | ||||
|                             ) | ||||
|                         }) | ||||
|                         .count() as u32) | ||||
|                         .into(), | ||||
|                 ) | ||||
|  | @ -2040,30 +2080,23 @@ pub fn sync_route( | |||
|         let mut edus = db | ||||
|             .rooms | ||||
|             .edus | ||||
|             .roomactives_all(&room_id) | ||||
|             .roomlatests_since(&room_id, since) | ||||
|             .unwrap() | ||||
|             .map(|r| r.unwrap()) | ||||
|             .collect::<Vec<_>>(); | ||||
| 
 | ||||
|         if edus.is_empty() { | ||||
|             edus.push( | ||||
|                 EduEvent::Typing(ruma_events::typing::TypingEvent { | ||||
|                     content: ruma_events::typing::TypingEventContent { | ||||
|                         user_ids: Vec::new(), | ||||
|                     }, | ||||
|                     room_id: None, // None because it can be inferred
 | ||||
|                 }) | ||||
|                 .into(), | ||||
|             ); | ||||
|         if db | ||||
|             .rooms | ||||
|             .edus | ||||
|             .last_roomactive_update(&room_id, &db.globals) | ||||
|             .unwrap() | ||||
|             > since | ||||
|         { | ||||
|             edus.push(serde_json::from_str(&serde_json::to_string( | ||||
|                 &EduEvent::Typing(db.rooms.edus.roomactives_all(&room_id).unwrap()), | ||||
|             ).unwrap()).unwrap()); | ||||
|         } | ||||
| 
 | ||||
|         edus.extend( | ||||
|             db.rooms | ||||
|                 .edus | ||||
|                 .roomlatests_since(&room_id, since) | ||||
|                 .unwrap() | ||||
|                 .map(|r| r.unwrap()), | ||||
|         ); | ||||
| 
 | ||||
|         joined_rooms.insert( | ||||
|             room_id.clone().try_into().unwrap(), | ||||
|             sync_events::JoinedRoom { | ||||
|  | @ -2130,7 +2163,17 @@ pub fn sync_route( | |||
|             .map(|r| r.unwrap()) | ||||
|             .collect::<Vec<_>>(); | ||||
| 
 | ||||
|         edus.extend(db.rooms.edus.roomactives_all(&room_id).map(|r| r.unwrap())); | ||||
|         if db | ||||
|             .rooms | ||||
|             .edus | ||||
|             .last_roomactive_update(&room_id, &db.globals) | ||||
|             .unwrap() | ||||
|             > since | ||||
|         { | ||||
|             edus.push(serde_json::from_str(&serde_json::to_string( | ||||
|                 &EduEvent::Typing(db.rooms.edus.roomactives_all(&room_id).unwrap()), | ||||
|             ).unwrap()).unwrap()); | ||||
|         } | ||||
| 
 | ||||
|         left_rooms.insert( | ||||
|             room_id.clone().try_into().unwrap(), | ||||
|  | @ -2218,7 +2261,7 @@ pub fn sync_route( | |||
|         } else { | ||||
|             None // TODO: left
 | ||||
|         }, | ||||
|         device_one_time_keys_count: Default::default(), | ||||
|         device_one_time_keys_count: Default::default(), // TODO
 | ||||
|         to_device: sync_events::ToDevice { | ||||
|             events: db | ||||
|                 .users | ||||
|  | @ -2281,7 +2324,6 @@ pub fn get_message_events_route( | |||
| 
 | ||||
| #[get("/_matrix/client/r0/voip/turnServer")] | ||||
| pub fn turn_server_route() -> MatrixResult<create_message_event::Response> { | ||||
|     warn!("TODO: turn_server_route"); | ||||
|     MatrixResult(Err(Error { | ||||
|         kind: ErrorKind::NotFound, | ||||
|         message: "There is no turn server yet.".to_owned(), | ||||
|  |  | |||
|  | @ -70,7 +70,10 @@ impl Database { | |||
|                 edus: rooms::RoomEdus { | ||||
|                     roomuserid_lastread: db.open_tree("roomuserid_lastread").unwrap(), // "Private" read receipt
 | ||||
|                     roomlatestid_roomlatest: db.open_tree("roomlatestid_roomlatest").unwrap(), // Read receipts
 | ||||
|                     roomactiveid_roomactive: db.open_tree("roomactiveid_roomactive").unwrap(), // Typing notifs
 | ||||
|                     roomactiveid_userid: db.open_tree("roomactiveid_userid").unwrap(), // Typing notifs
 | ||||
|                     roomid_lastroomactiveupdate: db | ||||
|                         .open_tree("roomid_lastroomactiveupdate") | ||||
|                         .unwrap(), | ||||
|                 }, | ||||
|                 pduid_pdu: db.open_tree("pduid_pdu").unwrap(), | ||||
|                 eventid_pduid: db.open_tree("eventid_pduid").unwrap(), | ||||
|  |  | |||
|  | @ -52,31 +52,6 @@ impl Rooms { | |||
|             .is_some()) | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Remove and replace with public room dir
 | ||||
|     /// Returns a vector over all rooms.
 | ||||
|     pub fn all_rooms(&self) -> Vec<RoomId> { | ||||
|         let mut room_ids = self | ||||
|             .roomid_pduleaves | ||||
|             .iter() | ||||
|             .keys() | ||||
|             .map(|key| { | ||||
|                 RoomId::try_from( | ||||
|                     &*utils::string_from_bytes( | ||||
|                         &key.unwrap() | ||||
|                             .iter() | ||||
|                             .copied() | ||||
|                             .take_while(|&x| x != 0xff) // until delimiter
 | ||||
|                             .collect::<Vec<_>>(), | ||||
|                     ) | ||||
|                     .unwrap(), | ||||
|                 ) | ||||
|                 .unwrap() | ||||
|             }) | ||||
|             .collect::<Vec<_>>(); | ||||
|         room_ids.dedup(); | ||||
|         room_ids | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the full room state.
 | ||||
|     pub fn room_state(&self, room_id: &RoomId) -> Result<HashMap<(EventType, String), PduEvent>> { | ||||
|         let mut hashmap = HashMap::new(); | ||||
|  | @ -329,15 +304,11 @@ impl Rooms { | |||
|                                 false | ||||
|                             } else if let member::MembershipState::Ban = current_membership { | ||||
|                                 false | ||||
|                             } else if join_rules == join_rules::JoinRule::Invite | ||||
|                                 && (current_membership == member::MembershipState::Join | ||||
|                                     || current_membership == member::MembershipState::Invite) | ||||
|                             { | ||||
|                                 true | ||||
|                             } else if join_rules == join_rules::JoinRule::Public { | ||||
|                                 true | ||||
|                             } else { | ||||
|                                 false | ||||
|                                 join_rules == join_rules::JoinRule::Invite | ||||
|                                     && (current_membership == member::MembershipState::Join | ||||
|                                         || current_membership == member::MembershipState::Invite) | ||||
|                                     || join_rules == join_rules::JoinRule::Public | ||||
|                             } | ||||
|                         } else if target_membership == member::MembershipState::Invite { | ||||
|                             if let Some(third_party_invite_json) = content.get("third_party_invite") | ||||
|  | @ -351,46 +322,35 @@ impl Rooms { | |||
|                                         )?; | ||||
|                                     todo!("handle third party invites"); | ||||
|                                 } | ||||
|                             } else if sender_membership != member::MembershipState::Join { | ||||
|                                 false | ||||
|                             } else if current_membership == member::MembershipState::Join | ||||
|                             } else if sender_membership != member::MembershipState::Join | ||||
|                                 || current_membership == member::MembershipState::Join | ||||
|                                 || current_membership == member::MembershipState::Ban | ||||
|                             { | ||||
|                                 false | ||||
|                             } else if sender_power | ||||
|                                 .filter(|&p| p >= &power_levels.invite) | ||||
|                                 .is_some() | ||||
|                             { | ||||
|                                 true | ||||
|                             } else { | ||||
|                                 false | ||||
|                                 sender_power | ||||
|                                     .filter(|&p| p >= &power_levels.invite) | ||||
|                                     .is_some() | ||||
|                             } | ||||
|                         } else if target_membership == member::MembershipState::Leave { | ||||
|                             if sender == target_user_id { | ||||
|                                 current_membership == member::MembershipState::Join | ||||
|                                     || current_membership == member::MembershipState::Invite | ||||
|                             } else if sender_membership != member::MembershipState::Join { | ||||
|                                 false | ||||
|                             } else if current_membership == member::MembershipState::Ban | ||||
|                                 && sender_power.filter(|&p| p < &power_levels.ban).is_some() | ||||
|                             } else if sender_membership != member::MembershipState::Join | ||||
|                                 || current_membership == member::MembershipState::Ban | ||||
|                                     && sender_power.filter(|&p| p < &power_levels.ban).is_some() | ||||
|                             { | ||||
|                                 false | ||||
|                             } else if sender_power.filter(|&p| p >= &power_levels.kick).is_some() | ||||
|                                 && target_power < sender_power | ||||
|                             { | ||||
|                                 true | ||||
|                             } else { | ||||
|                                 false | ||||
|                                 sender_power.filter(|&p| p >= &power_levels.kick).is_some() | ||||
|                                     && target_power < sender_power | ||||
|                             } | ||||
|                         } else if target_membership == member::MembershipState::Ban { | ||||
|                             if sender_membership != member::MembershipState::Join { | ||||
|                                 false | ||||
|                             } else if sender_power.filter(|&p| p >= &power_levels.ban).is_some() | ||||
|                                 && target_power < sender_power | ||||
|                             { | ||||
|                                 true | ||||
|                             } else { | ||||
|                                 false | ||||
|                                 sender_power.filter(|&p| p >= &power_levels.ban).is_some() | ||||
|                                     && target_power < sender_power | ||||
|                             } | ||||
|                         } else { | ||||
|                             false | ||||
|  | @ -668,16 +628,21 @@ impl Rooms { | |||
|         globals: &super::globals::Globals, | ||||
|     ) -> Result<()> { | ||||
|         if let Some(room_id) = room_id { | ||||
|             // New alias
 | ||||
|             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?)?; | ||||
|                 } | ||||
|             // room_id=None means remove alias
 | ||||
|             let room_id = self | ||||
|                 .alias_roomid | ||||
|                 .remove(alias.alias())? | ||||
|                 .ok_or(Error::BadRequest("Alias does not exist"))?; | ||||
| 
 | ||||
|             for key in self.aliasid_alias.scan_prefix(room_id).keys() { | ||||
|                 self.aliasid_alias.remove(key?)?; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| use crate::{utils, Result}; | ||||
| use crate::{utils, Error, Result}; | ||||
| use ruma_events::{collections::only::Event as EduEvent, EventJson}; | ||||
| use ruma_identifiers::{RoomId, UserId}; | ||||
| use std::convert::TryFrom; | ||||
| 
 | ||||
| pub struct RoomEdus { | ||||
|     pub(in super::super) roomuserid_lastread: sled::Tree, // RoomUserId = Room + User
 | ||||
|     pub(in super::super) roomlatestid_roomlatest: sled::Tree, // Read Receipts, RoomLatestId = RoomId + Count + UserId
 | ||||
|     pub(in super::super) roomactiveid_roomactive: sled::Tree, // Typing, RoomActiveId = RoomId + TimeoutTime + Count
 | ||||
|     pub(in super::super) roomactiveid_userid: sled::Tree, // Typing, RoomActiveId = RoomId + TimeoutTime + Count
 | ||||
|     pub(in super::super) roomid_lastroomactiveupdate: sled::Tree, // LastRoomActiveUpdate = Count
 | ||||
| } | ||||
| 
 | ||||
| impl RoomEdus { | ||||
|  | @ -79,10 +81,11 @@ impl RoomEdus { | |||
|             .map(|(_, v)| Ok(serde_json::from_slice(&v)?))) | ||||
|     } | ||||
| 
 | ||||
|     /// Adds an event that will be saved until the `timeout` timestamp (e.g. typing notifications).
 | ||||
|     /// Sets a user as typing until the timeout timestamp is reached or roomactive_remove is
 | ||||
|     /// called.
 | ||||
|     pub fn roomactive_add( | ||||
|         &self, | ||||
|         event: EduEvent, | ||||
|         user_id: &UserId, | ||||
|         room_id: &RoomId, | ||||
|         timeout: u64, | ||||
|         globals: &super::super::globals::Globals, | ||||
|  | @ -90,9 +93,73 @@ impl RoomEdus { | |||
|         let mut prefix = room_id.to_string().as_bytes().to_vec(); | ||||
|         prefix.push(0xff); | ||||
| 
 | ||||
|         // Cleanup all outdated edus before inserting a new one
 | ||||
|         let count = globals.next_count()?.to_be_bytes(); | ||||
| 
 | ||||
|         let mut room_active_id = prefix; | ||||
|         room_active_id.extend_from_slice(&timeout.to_be_bytes()); | ||||
|         room_active_id.push(0xff); | ||||
|         room_active_id.extend_from_slice(&count); | ||||
| 
 | ||||
|         self.roomactiveid_userid | ||||
|             .insert(&room_active_id, &*user_id.to_string().as_bytes())?; | ||||
| 
 | ||||
|         self.roomid_lastroomactiveupdate | ||||
|             .insert(&room_id.to_string().as_bytes(), &count)?; | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Removes a user from typing before the timeout is reached.
 | ||||
|     pub fn roomactive_remove( | ||||
|         &self, | ||||
|         user_id: &UserId, | ||||
|         room_id: &RoomId, | ||||
|         globals: &super::super::globals::Globals, | ||||
|     ) -> Result<()> { | ||||
|         let mut prefix = room_id.to_string().as_bytes().to_vec(); | ||||
|         prefix.push(0xff); | ||||
| 
 | ||||
|         let user_id = user_id.to_string(); | ||||
| 
 | ||||
|         let mut found_outdated = false; | ||||
| 
 | ||||
|         // Maybe there are multiple ones from calling roomactive_add multiple times
 | ||||
|         for outdated_edu in self | ||||
|             .roomactiveid_roomactive | ||||
|             .roomactiveid_userid | ||||
|             .scan_prefix(&prefix) | ||||
|             .filter_map(|r| r.ok()) | ||||
|             .filter(|(_, v)| v == user_id.as_bytes()) | ||||
|         { | ||||
|             self.roomactiveid_userid.remove(outdated_edu.0)?; | ||||
|             found_outdated = true; | ||||
|         } | ||||
| 
 | ||||
|         if found_outdated { | ||||
|             self.roomid_lastroomactiveupdate.insert( | ||||
|                 &room_id.to_string().as_bytes(), | ||||
|                 &globals.next_count()?.to_be_bytes(), | ||||
|             )?; | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Makes sure that typing events with old timestamps get removed.
 | ||||
|     fn roomactives_maintain( | ||||
|         &self, | ||||
|         room_id: &RoomId, | ||||
|         globals: &super::super::globals::Globals, | ||||
|     ) -> Result<()> { | ||||
|         let mut prefix = room_id.to_string().as_bytes().to_vec(); | ||||
|         prefix.push(0xff); | ||||
| 
 | ||||
|         let current_timestamp = utils::millis_since_unix_epoch(); | ||||
| 
 | ||||
|         let mut found_outdated = false; | ||||
| 
 | ||||
|         // Find all outdated edus before inserting a new one
 | ||||
|         for outdated_edu in self | ||||
|             .roomactiveid_userid | ||||
|             .scan_prefix(&prefix) | ||||
|             .keys() | ||||
|             .filter_map(|r| r.ok()) | ||||
|  | @ -101,60 +168,59 @@ impl RoomEdus { | |||
|                     k.split(|&c| c == 0xff) | ||||
|                         .nth(1) | ||||
|                         .expect("roomactive has valid timestamp and delimiters"), | ||||
|                 ) < utils::millis_since_unix_epoch() | ||||
|                 ) < current_timestamp | ||||
|             }) | ||||
|         { | ||||
|             // This is an outdated edu (time > timestamp)
 | ||||
|             self.roomlatestid_roomlatest.remove(outdated_edu)?; | ||||
|             found_outdated = true; | ||||
|         } | ||||
| 
 | ||||
|         let mut room_active_id = prefix; | ||||
|         room_active_id.extend_from_slice(&timeout.to_be_bytes()); | ||||
|         room_active_id.push(0xff); | ||||
|         room_active_id.extend_from_slice(&globals.next_count()?.to_be_bytes()); | ||||
| 
 | ||||
|         self.roomactiveid_roomactive | ||||
|             .insert(room_active_id, &*serde_json::to_string(&event)?)?; | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Removes an active event manually (before the timeout is reached).
 | ||||
|     pub fn roomactive_remove(&self, event: EduEvent, room_id: &RoomId) -> Result<()> { | ||||
|         let mut prefix = room_id.to_string().as_bytes().to_vec(); | ||||
|         prefix.push(0xff); | ||||
| 
 | ||||
|         let json = serde_json::to_string(&event)?; | ||||
| 
 | ||||
|         // Remove outdated entries
 | ||||
|         for outdated_edu in self | ||||
|             .roomactiveid_roomactive | ||||
|             .scan_prefix(&prefix) | ||||
|             .filter_map(|r| r.ok()) | ||||
|             .filter(|(_, v)| v == json.as_bytes()) | ||||
|         { | ||||
|             self.roomactiveid_roomactive.remove(outdated_edu.0)?; | ||||
|         if found_outdated { | ||||
|             self.roomid_lastroomactiveupdate.insert( | ||||
|                 &room_id.to_string().as_bytes(), | ||||
|                 &globals.next_count()?.to_be_bytes(), | ||||
|             )?; | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns an iterator over all active events (e.g. typing notifications).
 | ||||
|     pub fn roomactives_all( | ||||
|     pub fn last_roomactive_update( | ||||
|         &self, | ||||
|         room_id: &RoomId, | ||||
|     ) -> impl Iterator<Item = Result<EventJson<EduEvent>>> { | ||||
|         globals: &super::super::globals::Globals, | ||||
|     ) -> Result<u64> { | ||||
|         self.roomactives_maintain(room_id, globals)?; | ||||
| 
 | ||||
|         Ok(self | ||||
|             .roomid_lastroomactiveupdate | ||||
|             .get(&room_id.to_string().as_bytes())? | ||||
|             .map(|bytes| utils::u64_from_bytes(&bytes)) | ||||
|             .unwrap_or(0)) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns an iterator over all active events (e.g. typing notifications).
 | ||||
|     pub fn roomactives_all(&self, room_id: &RoomId) -> Result<ruma_events::typing::TypingEvent> { | ||||
|         let mut prefix = room_id.to_string().as_bytes().to_vec(); | ||||
|         prefix.push(0xff); | ||||
| 
 | ||||
|         let mut first_active_edu = prefix.clone(); | ||||
|         first_active_edu.extend_from_slice(&utils::millis_since_unix_epoch().to_be_bytes()); | ||||
|         let mut user_ids = Vec::new(); | ||||
| 
 | ||||
|         self.roomactiveid_roomactive | ||||
|             .range(first_active_edu..) | ||||
|             .filter_map(|r| r.ok()) | ||||
|             .take_while(move |(k, _)| k.starts_with(&prefix)) | ||||
|             .map(|(_, v)| Ok(serde_json::from_slice(&v)?)) | ||||
|         for user_id in self | ||||
|             .roomactiveid_userid | ||||
|             .scan_prefix(prefix) | ||||
|             .values() | ||||
|             .map(|user_id| Ok::<_, Error>(UserId::try_from(utils::string_from_bytes(&user_id?)?)?)) | ||||
|         { | ||||
|             user_ids.push(user_id?); | ||||
|         } | ||||
| 
 | ||||
|         Ok(ruma_events::typing::TypingEvent { | ||||
|             content: ruma_events::typing::TypingEventContent { user_ids }, | ||||
|             room_id: None, // Can be inferred
 | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /// Sets a private read marker at `count`.
 | ||||
|  |  | |||
|  | @ -361,14 +361,12 @@ impl Users { | |||
| 
 | ||||
|         self.userdeviceid_devicekeys.scan_prefix(key).map(|r| { | ||||
|             let (key, value) = r?; | ||||
|             Ok(( | ||||
|                 utils::string_from_bytes( | ||||
|                     key.rsplit(|&b| b == 0xff) | ||||
|                         .next() | ||||
|                         .ok_or(Error::BadDatabase("userdeviceid is invalid"))?, | ||||
|                 )?, | ||||
|                 serde_json::from_slice(&*value)?, | ||||
|             )) | ||||
|             let userdeviceid = utils::string_from_bytes( | ||||
|                 key.rsplit(|&b| b == 0xff) | ||||
|                     .next() | ||||
|                     .ok_or(Error::BadDatabase("userdeviceid is invalid"))?, | ||||
|             )?; | ||||
|             Ok((userdeviceid, serde_json::from_slice(&*value)?)) | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										13
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/main.rs
									
									
									
									
									
								
							|  | @ -6,12 +6,9 @@ mod database; | |||
| mod error; | ||||
| mod pdu; | ||||
| mod ruma_wrapper; | ||||
| mod server_server; | ||||
| //mod server_server;
 | ||||
| mod utils; | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod test; | ||||
| 
 | ||||
| pub use database::Database; | ||||
| pub use error::{Error, Result}; | ||||
| pub use pdu::PduEvent; | ||||
|  | @ -87,10 +84,10 @@ fn setup_rocket() -> rocket::Rocket { | |||
|                 client_server::delete_device_route, | ||||
|                 client_server::delete_devices_route, | ||||
|                 client_server::options_route, | ||||
|                 server_server::well_known_server, | ||||
|                 server_server::get_server_version, | ||||
|                 server_server::get_server_keys, | ||||
|                 server_server::get_server_keys_deprecated, | ||||
|                 //server_server::well_known_server,
 | ||||
|                 //server_server::get_server_version,
 | ||||
|                 //server_server::get_server_keys,
 | ||||
|                 //server_server::get_server_keys_deprecated,
 | ||||
|             ], | ||||
|         ) | ||||
|         .attach(AdHoc::on_attach("Config", |rocket| { | ||||
|  |  | |||
							
								
								
									
										124
									
								
								src/test.rs
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								src/test.rs
									
									
									
									
									
								
							|  | @ -1,124 +0,0 @@ | |||
| use super::*; | ||||
| use rocket::local::Client; | ||||
| use serde_json::{json, Value}; | ||||
| 
 | ||||
| fn setup_client() -> Client { | ||||
|     Database::try_remove("localhost"); | ||||
|     let rocket = setup_rocket(); | ||||
|     Client::new(rocket).expect("valid rocket instance") | ||||
| } | ||||
| 
 | ||||
| #[tokio::test] | ||||
| async fn register_login() { | ||||
|     let client = setup_client(); | ||||
|     let mut response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration_init()) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); | ||||
| 
 | ||||
|     assert_eq!(response.status().code, 401); | ||||
|     assert!(dbg!(&body["flows"]).as_array().unwrap().len() > 0); | ||||
|     assert!(body["session"].as_str().unwrap().len() > 0); | ||||
| } | ||||
| 
 | ||||
| #[tokio::test] | ||||
| async fn login_after_register_correct_password() { | ||||
|     let client = setup_client(); | ||||
|     let mut response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration_init()) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); | ||||
|     let session = body["session"].clone(); | ||||
| 
 | ||||
|     let response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration(session.as_str().unwrap())) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     assert_eq!(response.status().code, 200); | ||||
| 
 | ||||
|     let login_response = client | ||||
|         .post("/_matrix/client/r0/login") | ||||
|         .body(login_with_password("ilovebananas")) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     assert_eq!(login_response.status().code, 200); | ||||
| } | ||||
| 
 | ||||
| #[tokio::test] | ||||
| async fn login_after_register_incorrect_password() { | ||||
|     let client = setup_client(); | ||||
|     let mut response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration_init()) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); | ||||
|     let session = body["session"].clone(); | ||||
| 
 | ||||
|     let response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration(session.as_str().unwrap())) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     assert_eq!(response.status().code, 200); | ||||
| 
 | ||||
|     let mut login_response = client | ||||
|         .post("/_matrix/client/r0/login") | ||||
|         .body(login_with_password("idontlovebananas")) | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     let body = serde_json::from_str::<Value>(&login_response.body_string().await.unwrap()).unwrap(); | ||||
|     assert_eq!( | ||||
|         body.as_object() | ||||
|             .unwrap() | ||||
|             .get("errcode") | ||||
|             .unwrap() | ||||
|             .as_str() | ||||
|             .unwrap(), | ||||
|         "M_FORBIDDEN" | ||||
|     ); | ||||
|     assert_eq!(login_response.status().code, 403); | ||||
| } | ||||
| 
 | ||||
| fn registration_init() -> &'static str { | ||||
|     r#"{
 | ||||
|     "username": "cheeky_monkey", | ||||
|     "password": "ilovebananas", | ||||
|     "device_id": "GHTYAJCE", | ||||
|     "initial_device_display_name": "Jungle Phone", | ||||
|     "inhibit_login": false | ||||
|             }"#
 | ||||
| } | ||||
| 
 | ||||
| fn registration(session: &str) -> String { | ||||
|     json!({ | ||||
|         "auth": { | ||||
|             "session": session, | ||||
|             "type": "m.login.dummy" | ||||
|         }, | ||||
|         "username": "cheeky_monkey", | ||||
|         "password": "ilovebananas", | ||||
|         "device_id": "GHTYAJCE", | ||||
|         "initial_device_display_name": "Jungle Phone", | ||||
|         "inhibit_login": false | ||||
|     }) | ||||
|     .to_string() | ||||
| } | ||||
| 
 | ||||
| fn login_with_password(password: &str) -> String { | ||||
|     json!({ | ||||
|         "type": "m.login.password", | ||||
|         "identifier": { | ||||
|             "type": "m.id.user", | ||||
|             "user": "cheeky_monkey" | ||||
|         }, | ||||
|         "password": password, | ||||
|         "initial_device_display_name": "Jungle Phone" | ||||
|     }) | ||||
|     .to_string() | ||||
| } | ||||
|  | @ -28,26 +28,13 @@ POST /login wrong password is rejected | |||
| POST /createRoom makes a private room | ||||
| POST /createRoom makes a private room with invites | ||||
| GET /rooms/:room_id/state/m.room.member/:user_id fetches my membership | ||||
| GET /rooms/:room_id/state/m.room.power_levels fetches powerlevels | ||||
| POST /join/:room_alias can join a room | ||||
| POST /join/:room_id can join a room | ||||
| POST /join/:room_id can join a room with custom content | ||||
| POST /join/:room_alias can join a room with custom content | ||||
| POST /rooms/:room_id/join can join a room | ||||
| POST /rooms/:room_id/leave can leave a room | ||||
| POST /rooms/:room_id/invite can send an invite | ||||
| POST /rooms/:room_id/ban can ban a user | ||||
| POST /rooms/:room_id/send/:event_type sends a message | ||||
| PUT /rooms/:room_id/send/:event_type/:txn_id sends a message | ||||
| PUT /rooms/:room_id/send/:event_type/:txn_id deduplicates the same txn id | ||||
| GET /rooms/:room_id/state/m.room.power_levels can fetch levels | ||||
| PUT /rooms/:room_id/state/m.room.power_levels can set levels | ||||
| PUT power_levels should not explode if the old power levels were empty | ||||
| Both GET and PUT work | ||||
| POST /rooms/:room_id/read_markers can create read marker | ||||
| User signups are forbidden from starting with '_' | ||||
| Request to logout with invalid an access token is rejected | ||||
| Request to logout without an access token is rejected | ||||
| Room creation reports m.room.create to myself | ||||
| Room creation reports m.room.member to myself | ||||
| Version responds 200 OK with valid structure | ||||
|  | @ -60,7 +47,6 @@ Can create filter | |||
| Should reject keys claiming to belong to a different user | ||||
| Can add account data | ||||
| Checking local federation server | ||||
| Alternative server names do not cause a routing loop | ||||
| Can read configuration endpoint | ||||
| AS cannot create users outside its own namespace | ||||
| Changing the actions of an unknown default rule fails with 404 | ||||
|  | @ -78,4 +64,16 @@ Trying to get push rules with unknown rule_id fails with 404 | |||
| GET /events with non-numeric 'limit' | ||||
| GET /events with negative 'limit' | ||||
| GET /events with non-numeric 'timeout' | ||||
| Getting push rules doesn't corrupt the cache SYN-390 | ||||
| Getting push rules doesn't corrupt the cache SYN-390 | ||||
| GET /publicRooms lists newly-created room | ||||
| PUT /directory/room/:room_alias creates alias | ||||
| 3pid invite join with wrong but valid signature are rejected | ||||
| 3pid invite join valid signature but revoked keys are rejected | ||||
| 3pid invite join valid signature but unreachable ID server are rejected | ||||
| query for user with no keys returns empty key dict | ||||
| Can upload without a file name | ||||
| Can upload with ASCII file name | ||||
| User appears in user directory | ||||
| User directory correctly update on display name change | ||||
| User in shared private room does appear in user directory | ||||
| User in dir while user still shares private rooms | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue