Newer
Older
use ruma_client_api::{
error::{Error, ErrorKind},
r0::{
account::register, alias::get_alias, membership::join_room_by_id,
message::create_message_event, session::login, sync::sync_events,
use ruma_events::{collections::all::Event, room::message::MessageEvent};
use std::{
collections::HashMap,
convert::{TryFrom, TryInto},
#[get("/_matrix/client/versions")]
fn get_supported_versions_route() -> MatrixResult<get_supported_versions::Response> {
MatrixResult(Ok(get_supported_versions::Response {
body: Ruma<register::Request>,
) -> MatrixResult<register::Response> {
"@{}:{}",
body.username.clone().unwrap_or("randomname".to_owned()),
data.hostname()
return MatrixResult(Err(Error {
kind: ErrorKind::InvalidUsername,
status_code: http::StatusCode::BAD_REQUEST,
return MatrixResult(Err(Error {
kind: ErrorKind::UserInUse,
message: "Desired user ID is already taken.".to_owned(),
status_code: http::StatusCode::BAD_REQUEST,
}));
}
// Create user
data.user_add(&user_id, body.password.clone());
// Generate new device id if the user didn't specify one
let device_id = body
.device_id
.clone()
.unwrap_or_else(|| "TODO:randomdeviceid".to_owned());
// Add device
data.device_add(&user_id, &device_id);
// Generate new token for the device
let token = "TODO:randomtoken".to_owned();
data.token_replace(&user_id, &device_id, token.clone());
home_server: data.hostname().to_owned(),
fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<login::Response> {
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Validate login method
let user_id =
if let (login::UserInfo::MatrixId(mut username), login::LoginInfo::Password { password }) =
(body.user.clone(), body.login_info.clone())
{
if !username.contains(':') {
username = format!("@{}:{}", username, data.hostname());
}
if let Ok(user_id) = (*username).try_into() {
if !data.user_exists(&user_id) {}
// Check password
if let Some(correct_password) = data.password_get(&user_id) {
if password == correct_password {
// Success!
user_id
} else {
debug!("Invalid password.");
return MatrixResult(Err(Error {
kind: ErrorKind::Unknown,
message: "".to_owned(),
status_code: http::StatusCode::FORBIDDEN,
}));
}
} else {
debug!("UserId does not exist (has no assigned password). Can't log in.");
return MatrixResult(Err(Error {
kind: ErrorKind::Forbidden,
message: "".to_owned(),
status_code: http::StatusCode::FORBIDDEN,
}));
}
} else {
debug!("Invalid UserId.");
kind: ErrorKind::Unknown,
message: "Bad login type.".to_owned(),
status_code: http::StatusCode::BAD_REQUEST,
}));
}
} else {
kind: ErrorKind::Unknown,
message: "Bad login type.".to_owned(),
};
// Generate new device id if the user didn't specify one
let device_id = body
.device_id
.clone()
.unwrap_or("TODO:randomdeviceid".to_owned());
data.device_add(&user_id, &device_id);
// Generate a new token for the device
let token = "TODO:randomtoken".to_owned();
data.token_replace(&user_id, &device_id, token.clone());
home_server: Some(data.hostname().to_owned()),
#[get("/_matrix/client/r0/directory/room/<room_alias>")]
fn get_alias_route(room_alias: String) -> MatrixResult<get_alias::Response> {
let room_id = match &*room_alias {
"#room:localhost" => "!xclkjvdlfj:localhost",
_ => {
return MatrixResult(Err(Error {
kind: ErrorKind::NotFound,
message: "Room not found.".to_owned(),
status_code: http::StatusCode::NOT_FOUND,
}
}
.try_into()
.unwrap();
MatrixResult(Ok(get_alias::Response {
room_id,
servers: vec!["localhost".to_owned()],
}))
}
#[post("/_matrix/client/r0/rooms/<_room_id>/join", data = "<body>")]
fn join_room_by_id_route(
_room_id: String,
body: Ruma<join_room_by_id::Request>,
) -> MatrixResult<join_room_by_id::Response> {
MatrixResult(Ok(join_room_by_id::Response {
room_id: body.room_id.clone(),
}))
}
#[put(
"/_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id>",
data = "<body>"
)]
fn create_message_event_route(
_room_id: String,
_event_type: String,
_txn_id: String,
body: Ruma<create_message_event::Request>,
) -> MatrixResult<create_message_event::Response> {
event_id: EventId::try_from("$thiswillbefilledinlater").unwrap(),
origin_server_ts: utils::millis_since_unix_epoch(),
room_id: Some(body.room_id.clone()),
sender: body.user_id.clone().expect("user is authenticated"),
unsigned: Map::default(),
});
let event_id = EventId::try_from(&*format!(
"${}",
ruma_signatures::reference_hash(&serde_json::to_value(&event).unwrap())
.expect("ruma can calculate reference hashes")
))
.expect("ruma's reference hashes are correct");
// Insert event id
if let Event::RoomMessage(message) = &mut event {
message.event_id = event_id.clone();
}
// Add PDU to the graph
data.pdu_append(&event_id, &body.room_id, event);
MatrixResult(Ok(create_message_event::Response { event_id }))
#[get("/_matrix/client/r0/sync", data = "<body>")]
fn sync_route(
data: State<Data>,
body: Ruma<sync_events::Request>,
) -> MatrixResult<sync_events::Response> {
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
let pdus = data.pdus_all();
let mut joined_rooms = HashMap::new();
joined_rooms.insert(
"!roomid:localhost".try_into().unwrap(),
sync_events::JoinedRoom {
account_data: sync_events::AccountData { events: Vec::new() },
summary: sync_events::RoomSummary {
heroes: Vec::new(),
joined_member_count: None,
invited_member_count: None,
},
unread_notifications: sync_events::UnreadNotificationsCount {
highlight_count: None,
notification_count: None,
},
timeline: sync_events::Timeline {
limited: None,
prev_batch: None,
events: todo!(),
},
state: sync_events::State { events: Vec::new() },
ephemeral: sync_events::Ephemeral { events: Vec::new() },
},
);
MatrixResult(Ok(sync_events::Response {
next_batch: String::new(),
rooms: sync_events::Rooms {
leave: Default::default(),
join: joined_rooms,
invite: Default::default(),
},
presence: sync_events::Presence { events: Vec::new() },
device_lists: Default::default(),
device_one_time_keys_count: Default::default(),
to_device: sync_events::ToDevice { events: Vec::new() },
}))
}
#[options("/<_segments..>")]
fn options_route(_segments: PathBuf) -> MatrixResult<create_message_event::Response> {
MatrixResult(Err(Error {
kind: ErrorKind::NotFound,
message: "Room not found.".to_owned(),
status_code: http::StatusCode::NOT_FOUND,
}))
}
// Log info by default
if let Err(_) = std::env::var("RUST_LOG") {
std::env::set_var("RUST_LOG", "matrixserver=debug,info");
let data = Data::load_or_create("localhost");
data.debug();
.mount(
"/",
routes![
get_supported_versions_route,
register_route,
get_alias_route,
join_room_by_id_route,
create_message_event_route,