Signing, basis for federation
This commit is contained in:
		
							parent
							
								
									9b79798e56
								
							
						
					
					
						commit
						b0d9ccdb2d
					
				
					 8 changed files with 137 additions and 35 deletions
				
			
		
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -1260,7 +1260,6 @@ dependencies = [ | |||
| [[package]] | ||||
| name = "ruma-federation-api" | ||||
| version = "0.0.1" | ||||
| source = "git+https://github.com/ruma/ruma-federation-api.git#5448c650f0a583382152d0f43f2dcf720d495390" | ||||
| dependencies = [ | ||||
|  "js_int", | ||||
|  "ruma-api", | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ ruma-identifiers = "0.15.1" | |||
| ruma-api = "0.16.0-rc.1" | ||||
| ruma-events = "0.19.0" | ||||
| ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git" } | ||||
| ruma-federation-api = { git = "https://github.com/ruma/ruma-federation-api.git" } | ||||
| ruma-federation-api = { path = "../ruma-federation-api" } | ||||
| pretty_env_logger = "0.4.0" | ||||
| log = "0.4.8" | ||||
| sled = "0.31.0" | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| use crate::{utils, Data, MatrixResult, Ruma}; | ||||
| use crate::{server_server, utils, Data, MatrixResult, Ruma}; | ||||
| 
 | ||||
| use log::debug; | ||||
| use rocket::{get, options, post, put, State}; | ||||
|  | @ -674,7 +674,8 @@ pub fn join_room_by_id_or_alias_route( | |||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         body.room_id_or_alias.try_into().unwrap() | ||||
|         todo!(); | ||||
|         //body.room_id_or_alias.try_into().unwrap()
 | ||||
|     }; | ||||
| 
 | ||||
|     if data.room_join( | ||||
|  | @ -725,8 +726,8 @@ pub fn invite_user_route( | |||
| } | ||||
| 
 | ||||
| #[post("/_matrix/client/r0/publicRooms", data = "<body>")] | ||||
| pub fn get_public_rooms_filtered_route( | ||||
|     data: State<Data>, | ||||
| pub async fn get_public_rooms_filtered_route( | ||||
|     data: State<'_, Data>, | ||||
|     body: Ruma<get_public_rooms_filtered::Request>, | ||||
| ) -> MatrixResult<get_public_rooms_filtered::Response> { | ||||
|     let mut chunk = data | ||||
|  | @ -752,6 +753,25 @@ pub fn get_public_rooms_filtered_route( | |||
|         }) | ||||
|         .collect::<Vec<_>>(); | ||||
| 
 | ||||
|     chunk.extend_from_slice( | ||||
|         &server_server::send_request( | ||||
|             &data, | ||||
|             "https://matrix.org".to_owned(), | ||||
|             ruma_federation_api::v1::get_public_rooms::Request { | ||||
|                 limit: None, | ||||
|                 since: None, | ||||
|                 include_all_networks: None, | ||||
|                 third_party_instance_id: None, | ||||
|             }, | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap() | ||||
|         .chunk | ||||
|         .into_iter() | ||||
|         .map(|c| serde_json::from_str(&serde_json::to_string(dbg!(&c)).unwrap()).unwrap()) | ||||
|         .collect::<Vec<_>>(), | ||||
|     ); | ||||
| 
 | ||||
|     chunk.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members)); | ||||
| 
 | ||||
|     let total_room_count_estimate = (chunk.len() as u32).into(); | ||||
|  |  | |||
|  | @ -457,7 +457,7 @@ impl Data { | |||
|         )) | ||||
|         .expect("ruma's reference hashes are correct"); | ||||
| 
 | ||||
|         let mut pdu_json = serde_json::to_value(pdu).unwrap(); | ||||
|         let mut pdu_json = serde_json::to_value(&pdu).unwrap(); | ||||
|         ruma_signatures::hash_and_sign_event(self.hostname(), self.keypair(), &mut pdu_json); | ||||
| 
 | ||||
|         self.pdu_leaves_replace(&room_id, &pdu.event_id); | ||||
|  | @ -483,7 +483,7 @@ impl Data { | |||
| 
 | ||||
|         self.db | ||||
|             .pduid_pdu | ||||
|             .insert(&pdu_id, &*serde_json::to_string(&pdu_json).unwrap()) | ||||
|             .insert(&pdu_id, &*pdu_json.to_string()) | ||||
|             .unwrap(); | ||||
| 
 | ||||
|         self.db | ||||
|  | @ -497,7 +497,10 @@ impl Data { | |||
|             key.extend_from_slice(pdu.kind.to_string().as_bytes()); | ||||
|             key.push(0xff); | ||||
|             key.extend_from_slice(state_key.to_string().as_bytes()); | ||||
|             self.db.roomstateid_pdu.insert(key, &*pdu_json).unwrap(); | ||||
|             self.db | ||||
|                 .roomstateid_pdu | ||||
|                 .insert(key, &*pdu_json.to_string()) | ||||
|                 .unwrap(); | ||||
|         } | ||||
| 
 | ||||
|         pdu.event_id | ||||
|  |  | |||
|  | @ -127,7 +127,7 @@ impl Database { | |||
|                 &*db.update_and_fetch("keypair", utils::generate_keypair) | ||||
|                     .unwrap() | ||||
|                     .unwrap(), | ||||
|                 "0.0.0".to_owned(), | ||||
|                 "key1".to_owned(), | ||||
|             ) | ||||
|             .unwrap(), | ||||
|             _db: db, | ||||
|  |  | |||
|  | @ -1,25 +1,89 @@ | |||
| use std::convert::TryInto; | ||||
| use log::error; | ||||
| use http::header::{HeaderValue, AUTHORIZATION}; | ||||
| use ruma_api::{ | ||||
|     error::{FromHttpRequestError, FromHttpResponseError}, | ||||
|     Endpoint, Outgoing, | ||||
| }; | ||||
| use std::convert::{TryFrom, TryInto}; | ||||
| 
 | ||||
| pub fn send_request<T: TryInto<http::Request<Vec<u8>>>>( | ||||
| pub async fn send_request<T: Endpoint>( | ||||
|     data: &crate::Data, | ||||
|     method: http::Method, | ||||
|     uri: String, | ||||
|     destination: String, | ||||
|     request: T, | ||||
| ) where | ||||
| ) -> Option<<T::Response as Outgoing>::Incoming> | ||||
| where | ||||
|     // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet.
 | ||||
|     // See https://github.com/rust-lang/rust/issues/54149
 | ||||
|     <T as Outgoing>::Incoming: TryFrom<http::Request<Vec<u8>>, Error = FromHttpRequestError>, | ||||
|     <T::Response as Outgoing>::Incoming: TryFrom< | ||||
|         http::Response<Vec<u8>>, | ||||
|         Error = FromHttpResponseError<<T as Endpoint>::ResponseError>, | ||||
|     >, | ||||
|     T::Error: std::fmt::Debug, | ||||
| { | ||||
|     let mut http_request: http::Request<_> = request.try_into().unwrap(); | ||||
|     let request_json = serde_json::to_value(http_request.body()).unwrap(); | ||||
|     let uri = destination.clone() + T::METADATA.path; | ||||
|     *http_request.uri_mut() = uri.parse().unwrap(); | ||||
| 
 | ||||
|     let body = http_request.body(); | ||||
|     let mut request_json = if !body.is_empty() { | ||||
|         serde_json::to_value(http_request.body()).unwrap() | ||||
|     } else { | ||||
|         serde_json::Map::new().into() | ||||
|     }; | ||||
| 
 | ||||
|     let request_map = request_json.as_object_mut().unwrap(); | ||||
| 
 | ||||
|     request_map.insert("method".to_owned(), method.to_string().into()); | ||||
|     request_map.insert("uri".to_owned(), uri.to_string().into()); | ||||
|     //TODO: request_map.insert("origin".to_owned(), data.origin().to_string().into());
 | ||||
|     request_map.insert("method".to_owned(), T::METADATA.method.to_string().into()); | ||||
|     request_map.insert("uri".to_owned(), uri.into()); | ||||
|     request_map.insert("origin".to_owned(), data.hostname().into()); | ||||
|     request_map.insert("destination".to_owned(), destination.to_string().into()); | ||||
| 
 | ||||
|     ruma_signatures::sign_json(data.hostname(), data.keypair(), &mut request_json).unwrap(); | ||||
|     let signature = request_json["signatures"]; | ||||
|     data.reqwest_client().execute(http_request.into()); | ||||
|     ruma_signatures::sign_json(data.hostname(), data.keypair(), dbg!(&mut request_json)).unwrap(); | ||||
|     let signatures = request_json["signatures"] | ||||
|         .as_object() | ||||
|         .unwrap() | ||||
|         .values() | ||||
|         .next() | ||||
|         .unwrap() | ||||
|         .as_object() | ||||
|         .unwrap() | ||||
|         .iter() | ||||
|         .map(|(k, v)| (k, v.as_str().unwrap())); | ||||
| 
 | ||||
|     for s in signatures { | ||||
|         http_request.headers_mut().insert(AUTHORIZATION, HeaderValue::from_str(dbg!(&format!("X-Matrix origin={},key=\"{}\",sig=\"{}\"", data.hostname(), s.0, s.1))).unwrap()); | ||||
|     } | ||||
| 
 | ||||
|     let reqwest_response = data | ||||
|         .reqwest_client() | ||||
|         .execute(dbg!(http_request.into())) | ||||
|         .await; | ||||
| 
 | ||||
|     // Because reqwest::Response -> http::Response is complicated:
 | ||||
|     match reqwest_response { | ||||
|         Ok(mut reqwest_response) => { | ||||
|             let status = reqwest_response.status(); | ||||
|             let mut http_response = http::Response::builder().status(status); | ||||
|             let headers = http_response.headers_mut().unwrap(); | ||||
| 
 | ||||
|             for (k, v) in reqwest_response.headers_mut().drain() { | ||||
|                 if let Some(key) = k { | ||||
|                     headers.insert(key, v); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             let body = reqwest_response | ||||
|                 .bytes() | ||||
|                 .await | ||||
|                 .unwrap() | ||||
|                 .into_iter() | ||||
|                 .collect(); | ||||
|             Some(<T::Response as Outgoing>::Incoming::try_from(dbg!(http_response.body(body).unwrap())).ok().unwrap()) | ||||
|         } | ||||
|         Err(e) => { | ||||
|             println!("ERROR: {}", e); | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										38
									
								
								src/test.rs
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								src/test.rs
									
									
									
									
									
								
							|  | @ -1,8 +1,7 @@ | |||
| use super::*; | ||||
| use rocket::{local::Client, http::Status}; | ||||
| use serde_json::Value; | ||||
| use serde_json::json; | ||||
| use rocket::{http::Status, local::Client}; | ||||
| use ruma_client_api::error::ErrorKind; | ||||
| use serde_json::{json, Value}; | ||||
| use std::time::Duration; | ||||
| 
 | ||||
| fn setup_client() -> Client { | ||||
|  | @ -19,7 +18,8 @@ async fn register_login() { | |||
|     let mut response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration_init()) | ||||
|         .dispatch().await; | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); | ||||
| 
 | ||||
|     assert_eq!(response.status().code, 401); | ||||
|  | @ -33,14 +33,16 @@ async fn login_after_register_correct_password() { | |||
|     let mut response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration_init()) | ||||
|         .dispatch().await; | ||||
|         .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; | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     assert_eq!(response.status().code, 200); | ||||
| 
 | ||||
|     let login_response = client | ||||
|  | @ -57,14 +59,16 @@ async fn login_after_register_incorrect_password() { | |||
|     let mut response = client | ||||
|         .post("/_matrix/client/r0/register?kind=user") | ||||
|         .body(registration_init()) | ||||
|         .dispatch().await; | ||||
|         .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; | ||||
|         .dispatch() | ||||
|         .await; | ||||
|     assert_eq!(response.status().code, 200); | ||||
| 
 | ||||
|     let mut login_response = client | ||||
|  | @ -73,7 +77,15 @@ async fn login_after_register_incorrect_password() { | |||
|         .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!( | ||||
|         body.as_object() | ||||
|             .unwrap() | ||||
|             .get("errcode") | ||||
|             .unwrap() | ||||
|             .as_str() | ||||
|             .unwrap(), | ||||
|         "M_FORBIDDEN" | ||||
|     ); | ||||
|     assert_eq!(login_response.status().code, 403); | ||||
| } | ||||
| 
 | ||||
|  | @ -98,7 +110,8 @@ fn registration(session: &str) -> String { | |||
|         "device_id": "GHTYAJCE", | ||||
|         "initial_device_display_name": "Jungle Phone", | ||||
|         "inhibit_login": false | ||||
|     }).to_string() | ||||
|     }) | ||||
|     .to_string() | ||||
| } | ||||
| 
 | ||||
| fn login_with_password(password: &str) -> String { | ||||
|  | @ -110,5 +123,6 @@ fn login_with_password(password: &str) -> String { | |||
|         }, | ||||
|         "password": password, | ||||
|         "initial_device_display_name": "Jungle Phone" | ||||
|     }).to_string() | ||||
| } | ||||
|     }) | ||||
|     .to_string() | ||||
| } | ||||
|  |  | |||
|  | @ -27,8 +27,10 @@ pub fn increment(old: Option<&[u8]>) -> Option<Vec<u8>> { | |||
| 
 | ||||
| pub fn generate_keypair(old: Option<&[u8]>) -> Option<Vec<u8>> { | ||||
|     Some( | ||||
|         /* | ||||
|         old.map(|s| s.to_vec()) | ||||
|             .unwrap_or_else(|| ruma_signatures::Ed25519KeyPair::generate().unwrap()), | ||||
|             .unwrap_or_else(|| */ | ||||
|         ruma_signatures::Ed25519KeyPair::generate().unwrap(), | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue