ruma_wrapper.rs (6106B)
1 /// From https://git.koesters.xyz/timo/conduit/src/commit/88d091fca1c1db9f238c7a42467f63a619201f8c/src/ruma_wrapper.rs 2 use crate::utils; 3 use log::warn; 4 use rocket::{ 5 data::{Data, FromData, FromDataFuture, Transform, TransformFuture, Transformed}, 6 http::Status, 7 response::{self, Responder}, 8 Outcome::*, 9 Request, State, 10 }; 11 use ruma::{api::Endpoint, identifiers::UserId}; 12 use std::{convert::TryInto, io::Cursor, ops::Deref}; 13 use tokio::io::AsyncReadExt; 14 15 const MESSAGE_LIMIT: u64 = 20 * 1024 * 1024; // 20 MB 16 17 /// This struct converts rocket requests into ruma structs by converting them into http requests 18 /// first. 19 pub struct Ruma<T> { 20 pub body: T, 21 pub user_id: Option<UserId>, 22 pub device_id: Option<String>, 23 pub json_body: Option<Box<serde_json::value::RawValue>>, // This is None when body is not a valid string 24 } 25 26 impl<'a, T: Endpoint> FromData<'a> for Ruma<T> { 27 type Error = (); // TODO: Better error handling 28 type Owned = Data; 29 type Borrowed = Self::Owned; 30 31 fn transform<'r>( 32 _req: &'r Request<'_>, 33 data: Data, 34 ) -> TransformFuture<'r, Self::Owned, Self::Error> { 35 Box::pin(async move { Transform::Owned(Success(data)) }) 36 } 37 38 fn from_data( 39 request: &'a Request<'_>, 40 outcome: Transformed<'a, Self>, 41 ) -> FromDataFuture<'a, Self, Self::Error> { 42 Box::pin(async move { 43 let data = rocket::try_outcome!(outcome.owned()); 44 45 let (user_id, device_id) = if T::METADATA.requires_authentication { 46 let db = request 47 .guard::<State<'_, crate::data::Data>>() 48 .await 49 .unwrap(); 50 51 // Get token from header or query value 52 let token = match request 53 .headers() 54 .get_one("Authorization") 55 .map(|s| s[7..].to_owned()) // Split off "Bearer " 56 .or_else(|| request.get_query_value("access_token").and_then(|r| r.ok())) 57 { 58 // TODO: M_MISSING_TOKEN 59 None => return Failure((Status::Unauthorized, ())), 60 Some(token) => token, 61 }; 62 63 // Check if token is valid 64 match db.users.find_from_token(&token).unwrap() { 65 // TODO: M_UNKNOWN_TOKEN 66 None => return Failure((Status::Unauthorized, ())), 67 Some((user_id, device_id)) => (Some(user_id), Some(device_id)), 68 } 69 } else { 70 (None, None) 71 }; 72 73 let mut http_request = http::Request::builder() 74 .uri(request.uri().to_string()) 75 .method(&*request.method().to_string()); 76 for header in request.headers().iter() { 77 http_request = http_request.header(header.name.as_str(), &*header.value); 78 } 79 80 let mut handle = data.open().take(MESSAGE_LIMIT); 81 let mut body = Vec::new(); 82 handle.read_to_end(&mut body).await.unwrap(); 83 84 let http_request = http_request.body(body.clone()).unwrap(); 85 log::info!("{:?}", http_request); 86 87 match T::try_from(http_request) { 88 Ok(t) => Success(Ruma { 89 body: t, 90 user_id, 91 device_id, 92 // TODO: Can we avoid parsing it again? (We only need this for append_pdu) 93 json_body: utils::string_from_bytes(&body) 94 .ok() 95 .and_then(|s| serde_json::value::RawValue::from_string(s).ok()), 96 }), 97 Err(e) => { 98 warn!("{:?}", e); 99 Failure((Status::BadRequest, ())) 100 } 101 } 102 }) 103 } 104 } 105 106 impl<T> Deref for Ruma<T> { 107 type Target = T; 108 109 fn deref(&self) -> &Self::Target { 110 &self.body 111 } 112 } 113 114 /// This struct converts ruma responses into rocket http responses. 115 pub struct MatrixResult<T, E = ruma::api::client::Error>(pub std::result::Result<T, E>); 116 117 impl<T, E> TryInto<http::Response<Vec<u8>>> for MatrixResult<T, E> 118 where 119 T: TryInto<http::Response<Vec<u8>>>, 120 E: Into<http::Response<Vec<u8>>>, 121 { 122 type Error = T::Error; 123 124 fn try_into(self) -> Result<http::Response<Vec<u8>>, T::Error> { 125 match self.0 { 126 Ok(t) => t.try_into(), 127 Err(e) => Ok(e.into()), 128 } 129 } 130 } 131 132 #[rocket::async_trait] 133 impl<'r, T, E> Responder<'r> for MatrixResult<T, E> 134 where 135 T: Send + TryInto<http::Response<Vec<u8>>>, 136 T::Error: Send, 137 E: Into<http::Response<Vec<u8>>> + Send, 138 { 139 async fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> { 140 let http_response: Result<http::Response<_>, _> = self.try_into(); 141 match http_response { 142 Ok(http_response) => { 143 let mut response = rocket::response::Response::build(); 144 145 let status = http_response.status(); 146 response.raw_status(status.into(), ""); 147 148 for header in http_response.headers() { 149 response 150 .raw_header(header.0.to_string(), header.1.to_str().unwrap().to_owned()); 151 } 152 153 response 154 .sized_body(Cursor::new(http_response.into_body())) 155 .await; 156 157 response.raw_header("Access-Control-Allow-Origin", "*"); 158 response.raw_header( 159 "Access-Control-Allow-Methods", 160 "GET, POST, PUT, DELETE, OPTIONS", 161 ); 162 response.raw_header( 163 "Access-Control-Allow-Headers", 164 "Origin, X-Requested-With, Content-Type, Accept, Authorization", 165 ); 166 response.ok() 167 } 168 Err(_) => Err(Status::InternalServerError), 169 } 170 } 171 } 172 173 impl<T, E> Deref for MatrixResult<T, E> { 174 type Target = Result<T, E>; 175 176 fn deref(&self) -> &Self::Target { 177 &self.0 178 } 179 }