From b0d9ccdb2db31e685e05b828669bec2a00b6b589 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 22 Apr 2020 11:53:06 +0200 Subject: [PATCH] Signing, basis for federation --- Cargo.lock | 1 - Cargo.toml | 2 +- src/client_server.rs | 28 ++++++++++++-- src/data.rs | 9 +++-- src/database.rs | 2 +- src/server_server.rs | 88 ++++++++++++++++++++++++++++++++++++++------ src/test.rs | 38 +++++++++++++------ src/utils.rs | 4 +- 8 files changed, 137 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d7eaf21..5e6dc73e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 5cf5412f..2a3a0b63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/client_server.rs b/src/client_server.rs index a0191423..c97ba80c 100644 --- a/src/client_server.rs +++ b/src/client_server.rs @@ -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 = "")] -pub fn get_public_rooms_filtered_route( - data: State, +pub async fn get_public_rooms_filtered_route( + data: State<'_, Data>, body: Ruma, ) -> MatrixResult { let mut chunk = data @@ -752,6 +753,25 @@ pub fn get_public_rooms_filtered_route( }) .collect::>(); + 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::>(), + ); + chunk.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members)); let total_room_count_estimate = (chunk.len() as u32).into(); diff --git a/src/data.rs b/src/data.rs index 08e5e59a..8b24c9da 100644 --- a/src/data.rs +++ b/src/data.rs @@ -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 diff --git a/src/database.rs b/src/database.rs index bc328473..73406c12 100644 --- a/src/database.rs +++ b/src/database.rs @@ -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, diff --git a/src/server_server.rs b/src/server_server.rs index 57f76cee..8f355c0e 100644 --- a/src/server_server.rs +++ b/src/server_server.rs @@ -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>>>( +pub async fn send_request( data: &crate::Data, - method: http::Method, - uri: String, destination: String, request: T, -) where +) -> Option<::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 + ::Incoming: TryFrom>, Error = FromHttpRequestError>, + ::Incoming: TryFrom< + http::Response>, + Error = FromHttpResponseError<::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(::Incoming::try_from(dbg!(http_response.body(body).unwrap())).ok().unwrap()) + } + Err(e) => { + println!("ERROR: {}", e); + None + } + } } diff --git a/src/test.rs b/src/test.rs index c3cefb16..87564365 100644 --- a/src/test.rs +++ b/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::(&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::(&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::(&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::(&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() -} \ No newline at end of file + }) + .to_string() +} diff --git a/src/utils.rs b/src/utils.rs index a3600360..07a99f1b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -27,8 +27,10 @@ pub fn increment(old: Option<&[u8]>) -> Option> { pub fn generate_keypair(old: Option<&[u8]>) -> Option> { Some( + /* old.map(|s| s.to_vec()) - .unwrap_or_else(|| ruma_signatures::Ed25519KeyPair::generate().unwrap()), + .unwrap_or_else(|| */ + ruma_signatures::Ed25519KeyPair::generate().unwrap(), ) }