Merge pull request 'Small fixes' (#98) from fix into master

next
Timo Kösters 2020-06-04 12:05:54 +02:00
commit c655870d23
10 changed files with 353 additions and 408 deletions

92
Cargo.lock generated
View File

@ -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",
]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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