Add auth
parent
18ed991b93
commit
533260edd8
|
@ -497,6 +497,7 @@ dependencies = [
|
||||||
"ruma-client-api",
|
"ruma-client-api",
|
||||||
"ruma-events",
|
"ruma-events",
|
||||||
"ruma-identifiers",
|
"ruma-identifiers",
|
||||||
|
"serde_json",
|
||||||
"sled",
|
"sled",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -807,9 +808,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-api"
|
name = "ruma-api"
|
||||||
version = "0.15.0-dev.1"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44987d5fefcf801a6fb5c5843c17f876a53852fa07e5e4d99e0dca3670f1441a"
|
checksum = "120f0cd8625b842423ef3a63cabb8c309ca35a02de87cc4b377fb2cdd43f1fe5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
|
@ -824,9 +825,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-api-macros"
|
name = "ruma-api-macros"
|
||||||
version = "0.12.0-dev.1"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36931db94874129f9202f650d91447d8317b099bae1e12cdd5769ba4eced07d2"
|
checksum = "bfc523efc9c1ba7033ff17888551c1d378e12eae087cfbe4fcee938ff516759e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9",
|
"proc-macro2 1.0.9",
|
||||||
"quote 1.0.3",
|
"quote 1.0.3",
|
||||||
|
@ -835,8 +836,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-client-api"
|
name = "ruma-client-api"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
source = "git+https://github.com/ruma/ruma-client-api#57f5e8d66168a54128426c8e34b26fa78f739c3e"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a64241cdc0cff76038484451d7a5d2689f8ea4e59b6695cd3c8448af7bcc016"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"js_int",
|
"js_int",
|
||||||
|
@ -851,9 +853,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-events"
|
name = "ruma-events"
|
||||||
version = "0.17.0"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11951235b25c72a82eb988aabf5af23cae883562665e0cb73954ffe4ae81f11c"
|
checksum = "80e34bfc20462f18d7f0beb6f1863db62d29438f2dcf390b625e9b20696cb2b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js_int",
|
"js_int",
|
||||||
"ruma-events-macros",
|
"ruma-events-macros",
|
||||||
|
@ -864,9 +866,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-events-macros"
|
name = "ruma-events-macros"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "962d93056619ed61826a9d8872c863560e4892ff6a69b70f593baa5ae8b19dc8"
|
checksum = "ff95b6b4480c570db471b490b35ad70add5470651654e75faf0b97052b4f29e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9",
|
"proc-macro2 1.0.9",
|
||||||
"quote 1.0.3",
|
"quote 1.0.3",
|
||||||
|
@ -994,9 +996,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.49"
|
version = "1.0.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02044a6a92866fd61624b3db4d2c9dccc2feabbc6be490b87611bf285edbac55"
|
checksum = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
|
|
@ -9,12 +9,13 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = { git = "https://github.com/SergioBenitez/Rocket.git", features = ["tls"] }
|
rocket = { git = "https://github.com/SergioBenitez/Rocket.git", features = ["tls"] }
|
||||||
http = "0.2.1"
|
http = "0.2.1"
|
||||||
ruma-client-api = { git = "https://github.com/ruma/ruma-client-api" }
|
ruma-client-api = "0.7.0"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
sled = "0.31.0"
|
sled = "0.31.0"
|
||||||
directories = "2.0.2"
|
directories = "2.0.2"
|
||||||
ruma-identifiers = "0.14.1"
|
ruma-identifiers = "0.14.1"
|
||||||
ruma-api = "0.15.0-dev.1"
|
ruma-api = "0.15.0"
|
||||||
ruma-events = "0.17.0"
|
ruma-events = "0.18.0"
|
||||||
js_int = "0.1.3"
|
js_int = "0.1.3"
|
||||||
|
serde_json = "1.0.50"
|
||||||
|
|
110
src/data.rs
110
src/data.rs
|
@ -1,16 +1,18 @@
|
||||||
|
use crate::utils;
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use ruma_events::collections::all::RoomEvent;
|
use ruma_events::collections::all::RoomEvent;
|
||||||
use ruma_identifiers::UserId;
|
use ruma_identifiers::UserId;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
const USERID_PASSWORD: &str = "userid_password";
|
||||||
|
const USERID_DEVICEIDS: &str = "userid_deviceids";
|
||||||
|
const DEVICEID_TOKEN: &str = "deviceid_token";
|
||||||
|
const TOKEN_USERID: &str = "token_userid";
|
||||||
|
|
||||||
pub struct Data(sled::Db);
|
pub struct Data(sled::Db);
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
pub fn set_hostname(&self, hostname: &str) {
|
/// Load an existing database or create a new one.
|
||||||
self.0.insert("hostname", hostname).unwrap();
|
|
||||||
}
|
|
||||||
pub fn hostname(&self) -> String {
|
|
||||||
String::from_utf8(self.0.get("hostname").unwrap().unwrap().to_vec()).unwrap()
|
|
||||||
}
|
|
||||||
pub fn load_or_create() -> Self {
|
pub fn load_or_create() -> Self {
|
||||||
Data(
|
Data(
|
||||||
sled::open(
|
sled::open(
|
||||||
|
@ -22,21 +24,109 @@ impl Data {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the hostname of the server. Warning: Hostname changes will likely break things.
|
||||||
|
pub fn set_hostname(&self, hostname: &str) {
|
||||||
|
self.0.insert("hostname", hostname).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hostname of the server.
|
||||||
|
pub fn hostname(&self) -> String {
|
||||||
|
utils::bytes_to_string(&self.0.get("hostname").unwrap().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a user has an account by looking for an assigned password.
|
||||||
pub fn user_exists(&self, user_id: &UserId) -> bool {
|
pub fn user_exists(&self, user_id: &UserId) -> bool {
|
||||||
self.0
|
self.0
|
||||||
.open_tree("username_password")
|
.open_tree(USERID_PASSWORD)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains_key(user_id.to_string())
|
.contains_key(user_id.to_string())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_add(&self, user_id: UserId, password: Option<String>) {
|
/// Create a new user account by assigning them a password.
|
||||||
|
pub fn user_add(&self, user_id: &UserId, password: Option<String>) {
|
||||||
self.0
|
self.0
|
||||||
.open_tree("username_password")
|
.open_tree(USERID_PASSWORD)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(user_id.to_string(), &*password.unwrap_or_default())
|
.insert(user_id.to_string(), &*password.unwrap_or_default())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn room_event_add(&self, room_event: &RoomEvent) {}
|
/// Find out which user an access token belongs to.
|
||||||
|
pub fn user_from_token(&self, token: &str) -> Option<UserId> {
|
||||||
|
self.0
|
||||||
|
.open_tree(TOKEN_USERID)
|
||||||
|
.unwrap()
|
||||||
|
.get(token)
|
||||||
|
.unwrap()
|
||||||
|
.and_then(|bytes| (*utils::bytes_to_string(&bytes)).try_into().ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the given password is equal to the one in the database.
|
||||||
|
pub fn password_get(&self, user_id: &UserId) -> Option<String> {
|
||||||
|
self.0
|
||||||
|
.open_tree(USERID_PASSWORD)
|
||||||
|
.unwrap()
|
||||||
|
.get(user_id.to_string())
|
||||||
|
.unwrap()
|
||||||
|
.map(|bytes| utils::bytes_to_string(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new device to a user.
|
||||||
|
pub fn device_add(&self, user_id: &UserId, device_id: &str) {
|
||||||
|
self.0
|
||||||
|
.open_tree(USERID_DEVICEIDS)
|
||||||
|
.unwrap()
|
||||||
|
.insert(user_id.to_string(), device_id)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace the access token of one device.
|
||||||
|
pub fn token_replace(&self, user_id: &UserId, device_id: &String, token: String) {
|
||||||
|
// Make sure the device id belongs to the user
|
||||||
|
debug_assert!(self
|
||||||
|
.0
|
||||||
|
.open_tree(USERID_DEVICEIDS)
|
||||||
|
.unwrap()
|
||||||
|
.get(&user_id.to_string()) // Does the user exist?
|
||||||
|
.unwrap()
|
||||||
|
.map(|bytes| utils::bytes_to_vec(&bytes))
|
||||||
|
.filter(|devices| devices.contains(device_id)) // Does the user have that device?
|
||||||
|
.is_some());
|
||||||
|
|
||||||
|
// Remove old token
|
||||||
|
if let Some(old_token) = self
|
||||||
|
.0
|
||||||
|
.open_tree(DEVICEID_TOKEN)
|
||||||
|
.unwrap()
|
||||||
|
.get(device_id)
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
self.0
|
||||||
|
.open_tree(TOKEN_USERID)
|
||||||
|
.unwrap()
|
||||||
|
.remove(old_token)
|
||||||
|
.unwrap();
|
||||||
|
// It will be removed from DEVICEID_TOKEN by the insert later
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign token to device_id
|
||||||
|
self.0
|
||||||
|
.open_tree(DEVICEID_TOKEN)
|
||||||
|
.unwrap()
|
||||||
|
.insert(device_id, &*token)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Assign token to user
|
||||||
|
self.0
|
||||||
|
.open_tree(TOKEN_USERID)
|
||||||
|
.unwrap()
|
||||||
|
.insert(token, &*user_id.to_string())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new room event.
|
||||||
|
pub fn room_event_add(&self, _room_event: &RoomEvent) {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
154
src/main.rs
154
src/main.rs
|
@ -14,9 +14,10 @@ use ruma_client_api::{
|
||||||
},
|
},
|
||||||
unversioned::get_supported_versions,
|
unversioned::get_supported_versions,
|
||||||
};
|
};
|
||||||
use ruma_events::room::message::MessageEvent;
|
use ruma_events::{room::message::MessageEvent, EventResult};
|
||||||
use ruma_identifiers::{EventId, UserId};
|
use ruma_identifiers::{EventId, UserId};
|
||||||
use ruma_wrapper::{MatrixResult, Ruma};
|
use ruma_wrapper::{MatrixResult, Ruma};
|
||||||
|
use serde_json::map::Map;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::{collections::HashMap, convert::TryInto};
|
use std::{collections::HashMap, convert::TryInto};
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ fn register_route(
|
||||||
data: State<Data>,
|
data: State<Data>,
|
||||||
body: Ruma<register::Request>,
|
body: Ruma<register::Request>,
|
||||||
) -> MatrixResult<register::Response> {
|
) -> MatrixResult<register::Response> {
|
||||||
|
// Validate user id
|
||||||
let user_id: UserId = match (*format!(
|
let user_id: UserId = match (*format!(
|
||||||
"@{}:{}",
|
"@{}:{}",
|
||||||
body.username.clone().unwrap_or("randomname".to_owned()),
|
body.username.clone().unwrap_or("randomname".to_owned()),
|
||||||
|
@ -59,6 +61,7 @@ fn register_route(
|
||||||
Ok(user_id) => user_id,
|
Ok(user_id) => user_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if username is creative enough
|
||||||
if data.user_exists(&user_id) {
|
if data.user_exists(&user_id) {
|
||||||
debug!("ID already taken");
|
debug!("ID already taken");
|
||||||
return MatrixResult(Err(Error {
|
return MatrixResult(Err(Error {
|
||||||
|
@ -68,68 +71,115 @@ fn register_route(
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
data.user_add(user_id.clone(), body.password.clone());
|
// 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());
|
||||||
|
|
||||||
MatrixResult(Ok(register::Response {
|
MatrixResult(Ok(register::Response {
|
||||||
access_token: "randomtoken".to_owned(),
|
access_token: token,
|
||||||
home_server: data.hostname(),
|
home_server: data.hostname(),
|
||||||
user_id,
|
user_id,
|
||||||
device_id: body.device_id.clone().unwrap_or("randomid".to_owned()),
|
device_id,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/_matrix/client/r0/login", data = "<body>")]
|
#[post("/_matrix/client/r0/login", data = "<body>")]
|
||||||
fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<login::Response> {
|
fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<login::Response> {
|
||||||
let username = if let login::UserInfo::MatrixId(mut username) = body.user.clone() {
|
// Validate login method
|
||||||
if !username.contains(':') {
|
let user_id =
|
||||||
username = format!("@{}:{}", username, data.hostname());
|
if let (login::UserInfo::MatrixId(mut username), login::LoginInfo::Password { password }) =
|
||||||
}
|
(body.user.clone(), body.login_info.clone())
|
||||||
if let Ok(user_id) = (*username).try_into() {
|
{
|
||||||
if !data.user_exists(&user_id) {
|
if !username.contains(':') {
|
||||||
debug!("Userid does not exist. Can't log in.");
|
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.");
|
||||||
return MatrixResult(Err(Error {
|
return MatrixResult(Err(Error {
|
||||||
kind: ErrorKind::Forbidden,
|
kind: ErrorKind::Unknown,
|
||||||
message: "UserId not found.".to_owned(),
|
message: "Bad login type.".to_owned(),
|
||||||
status_code: http::StatusCode::BAD_REQUEST,
|
status_code: http::StatusCode::BAD_REQUEST,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
user_id
|
|
||||||
} else {
|
} else {
|
||||||
debug!("Invalid UserId.");
|
debug!("Bad login type");
|
||||||
return MatrixResult(Err(Error {
|
return MatrixResult(Err(Error {
|
||||||
kind: ErrorKind::Unknown,
|
kind: ErrorKind::Unknown,
|
||||||
message: "Bad login type.".to_owned(),
|
message: "Bad login type.".to_owned(),
|
||||||
status_code: http::StatusCode::BAD_REQUEST,
|
status_code: http::StatusCode::BAD_REQUEST,
|
||||||
}));
|
}));
|
||||||
}
|
};
|
||||||
} else {
|
|
||||||
debug!("Bad login type");
|
// Generate new device id if the user didn't specify one
|
||||||
return MatrixResult(Err(Error {
|
let device_id = body
|
||||||
kind: ErrorKind::Unknown,
|
.device_id
|
||||||
message: "Bad login type.".to_owned(),
|
.clone()
|
||||||
status_code: http::StatusCode::BAD_REQUEST,
|
.unwrap_or("TODO:randomdeviceid".to_owned());
|
||||||
}));
|
|
||||||
};
|
// Add device (TODO: We might not want to call it when using an existing device)
|
||||||
|
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());
|
||||||
|
|
||||||
return MatrixResult(Ok(login::Response {
|
return MatrixResult(Ok(login::Response {
|
||||||
user_id: username.try_into().unwrap(), // Unwrap is okay because the user is already registered
|
user_id,
|
||||||
access_token: "randomtoken".to_owned(),
|
access_token: token,
|
||||||
home_server: Some("localhost".to_owned()),
|
home_server: Some(data.hostname()),
|
||||||
device_id: body.device_id.clone().unwrap_or("randomid".to_owned()),
|
device_id,
|
||||||
well_known: None,
|
well_known: None,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/_matrix/client/r0/directory/room/<room_alias>")]
|
#[get("/_matrix/client/r0/directory/room/<room_alias>")]
|
||||||
fn get_alias_route(room_alias: String) -> MatrixResult<get_alias::Response> {
|
fn get_alias_route(room_alias: String) -> MatrixResult<get_alias::Response> {
|
||||||
|
// TODO
|
||||||
let room_id = match &*room_alias {
|
let room_id = match &*room_alias {
|
||||||
"#room:localhost" => "!xclkjvdlfj:localhost",
|
"#room:localhost" => "!xclkjvdlfj:localhost",
|
||||||
_ => {
|
_ => {
|
||||||
|
debug!("Room not found.");
|
||||||
return MatrixResult(Err(Error {
|
return MatrixResult(Err(Error {
|
||||||
kind: ErrorKind::NotFound,
|
kind: ErrorKind::NotFound,
|
||||||
message: "Room not found.".to_owned(),
|
message: "Room not found.".to_owned(),
|
||||||
status_code: http::StatusCode::NOT_FOUND,
|
status_code: http::StatusCode::NOT_FOUND,
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.try_into()
|
.try_into()
|
||||||
|
@ -146,6 +196,7 @@ fn join_room_by_id_route(
|
||||||
_room_id: String,
|
_room_id: String,
|
||||||
body: Ruma<join_room_by_id::Request>,
|
body: Ruma<join_room_by_id::Request>,
|
||||||
) -> MatrixResult<join_room_by_id::Response> {
|
) -> MatrixResult<join_room_by_id::Response> {
|
||||||
|
// TODO
|
||||||
MatrixResult(Ok(join_room_by_id::Response {
|
MatrixResult(Ok(join_room_by_id::Response {
|
||||||
room_id: body.room_id.clone(),
|
room_id: body.room_id.clone(),
|
||||||
}))
|
}))
|
||||||
|
@ -162,23 +213,34 @@ fn create_message_event_route(
|
||||||
_txn_id: String,
|
_txn_id: String,
|
||||||
body: Ruma<create_message_event::Request>,
|
body: Ruma<create_message_event::Request>,
|
||||||
) -> MatrixResult<create_message_event::Response> {
|
) -> MatrixResult<create_message_event::Response> {
|
||||||
dbg!(&body);
|
// Check if content is valid
|
||||||
if let Ok(content) = body.data.clone().into_result() {
|
let content = match body.data.clone() {
|
||||||
data.room_event_add(
|
EventResult::Ok(content) => content,
|
||||||
&MessageEvent {
|
EventResult::Err(_) => {
|
||||||
content,
|
debug!("No content.");
|
||||||
event_id: EventId::try_from("$randomeventid:localhost").unwrap(),
|
return MatrixResult(Err(Error {
|
||||||
origin_server_ts: utils::millis_since_unix_epoch(),
|
kind: ErrorKind::NotFound,
|
||||||
room_id: Some(body.room_id.clone()),
|
message: "No content.".to_owned(),
|
||||||
sender: UserId::try_from("@TODO:localhost").unwrap(),
|
status_code: http::StatusCode::BAD_REQUEST,
|
||||||
unsigned: None,
|
}));
|
||||||
}
|
}
|
||||||
.into(),
|
};
|
||||||
);
|
|
||||||
}
|
let event_id = EventId::try_from("$TODOrandomeventid:localhost").unwrap();
|
||||||
MatrixResult(Ok(create_message_event::Response {
|
|
||||||
event_id: "$randomeventid:localhost".try_into().unwrap(),
|
data.room_event_add(
|
||||||
}))
|
&MessageEvent {
|
||||||
|
content,
|
||||||
|
event_id: event_id.clone(),
|
||||||
|
origin_server_ts: utils::millis_since_unix_epoch(),
|
||||||
|
room_id: Some(body.room_id.clone()),
|
||||||
|
sender: body.user_id.expect("user is authenticated"),
|
||||||
|
unsigned: Map::default(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
MatrixResult(Ok(create_message_event::Response { event_id }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -10,10 +10,10 @@ use {
|
||||||
Endpoint, Outgoing,
|
Endpoint, Outgoing,
|
||||||
},
|
},
|
||||||
ruma_client_api::error::Error,
|
ruma_client_api::error::Error,
|
||||||
|
ruma_identifiers::UserId,
|
||||||
std::ops::Deref,
|
std::ops::Deref,
|
||||||
std::{
|
std::{
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
fmt,
|
|
||||||
io::{Cursor, Read},
|
io::{Cursor, Read},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -22,9 +22,10 @@ const MESSAGE_LIMIT: u64 = 65535;
|
||||||
|
|
||||||
/// This struct converts rocket requests into ruma structs by converting them into http requests
|
/// This struct converts rocket requests into ruma structs by converting them into http requests
|
||||||
/// first.
|
/// first.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Ruma<T: Outgoing> {
|
pub struct Ruma<T: Outgoing> {
|
||||||
body: T::Incoming,
|
body: T::Incoming,
|
||||||
headers: http::HeaderMap<http::header::HeaderValue>,
|
pub user_id: Option<UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Endpoint> FromDataSimple for Ruma<T>
|
impl<T: Endpoint> FromDataSimple for Ruma<T>
|
||||||
|
@ -37,9 +38,34 @@ where
|
||||||
Error = FromHttpResponseError<<T as Endpoint>::ResponseError>,
|
Error = FromHttpResponseError<<T as Endpoint>::ResponseError>,
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
type Error = ();
|
type Error = (); // TODO: Better error handling
|
||||||
|
|
||||||
fn from_data(request: &Request, data: rocket::Data) -> Outcome<Self, Self::Error> {
|
fn from_data(request: &Request, data: rocket::Data) -> Outcome<Self, Self::Error> {
|
||||||
|
let user_id = if T::METADATA.requires_authentication {
|
||||||
|
let data = request.guard::<State<crate::Data>>().unwrap();
|
||||||
|
|
||||||
|
// Get token from header or query value
|
||||||
|
let token = match request
|
||||||
|
.headers()
|
||||||
|
.get_one("Authorization")
|
||||||
|
.map(|s| s.to_owned())
|
||||||
|
.or_else(|| request.get_query_value("access_token").and_then(|r| r.ok()))
|
||||||
|
{
|
||||||
|
// TODO: M_MISSING_TOKEN
|
||||||
|
None => return Failure((Status::Unauthorized, ())),
|
||||||
|
Some(token) => token,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if token is valid
|
||||||
|
match data.user_from_token(&token) {
|
||||||
|
// TODO: M_UNKNOWN_TOKEN
|
||||||
|
None => return Failure((Status::Unauthorized, ())),
|
||||||
|
Some(user_id) => Some(user_id),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut http_request = http::Request::builder()
|
let mut http_request = http::Request::builder()
|
||||||
.uri(request.uri().to_string())
|
.uri(request.uri().to_string())
|
||||||
.method(&*request.method().to_string());
|
.method(&*request.method().to_string());
|
||||||
|
@ -52,17 +78,10 @@ where
|
||||||
handle.read_to_end(&mut body).unwrap();
|
handle.read_to_end(&mut body).unwrap();
|
||||||
|
|
||||||
let http_request = http_request.body(body).unwrap();
|
let http_request = http_request.body(body).unwrap();
|
||||||
let headers = http_request.headers().clone();
|
|
||||||
|
|
||||||
log::info!("{:?}", http_request);
|
log::info!("{:?}", http_request);
|
||||||
match T::Incoming::try_from(http_request) {
|
match T::Incoming::try_from(http_request) {
|
||||||
Ok(t) => {
|
Ok(t) => Success(Ruma { body: t, user_id }),
|
||||||
if T::METADATA.requires_authentication {
|
|
||||||
let data = request.guard::<State<crate::Data>>();
|
|
||||||
// TODO: auth
|
|
||||||
}
|
|
||||||
Success(Ruma { body: t, headers })
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
Failure((Status::InternalServerError, ()))
|
Failure((Status::InternalServerError, ()))
|
||||||
|
@ -79,18 +98,6 @@ impl<T: Outgoing> Deref for Ruma<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Outgoing> fmt::Debug for Ruma<T>
|
|
||||||
where
|
|
||||||
T::Incoming: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Ruma")
|
|
||||||
.field("body", &self.body)
|
|
||||||
.field("headers", &self.headers)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This struct converts ruma responses into rocket http responses.
|
/// This struct converts ruma responses into rocket http responses.
|
||||||
pub struct MatrixResult<T>(pub std::result::Result<T, Error>);
|
pub struct MatrixResult<T>(pub std::result::Result<T, Error>);
|
||||||
impl<T: TryInto<http::Response<Vec<u8>>>> TryInto<http::Response<Vec<u8>>> for MatrixResult<T> {
|
impl<T: TryInto<http::Response<Vec<u8>>>> TryInto<http::Response<Vec<u8>>> for MatrixResult<T> {
|
||||||
|
|
18
src/utils.rs
18
src/utils.rs
|
@ -7,3 +7,21 @@ pub fn millis_since_unix_epoch() -> js_int::UInt {
|
||||||
.as_millis() as u32)
|
.as_millis() as u32)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bytes_to_string(bytes: &[u8]) -> String {
|
||||||
|
String::from_utf8(bytes.to_vec()).expect("convert bytes to string")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vec_to_bytes(vec: Vec<String>) -> Vec<u8> {
|
||||||
|
vec.into_iter()
|
||||||
|
.map(|string| string.into_bytes())
|
||||||
|
.collect::<Vec<Vec<u8>>>()
|
||||||
|
.join(&0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_to_vec(bytes: &[u8]) -> Vec<String> {
|
||||||
|
bytes
|
||||||
|
.split(|&b| b == 0)
|
||||||
|
.map(|bytes_string| bytes_to_string(bytes_string))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue