Signing, basis for federation

next
timokoesters 2020-04-22 11:53:06 +02:00
parent 9b79798e56
commit b0d9ccdb2d
No known key found for this signature in database
GPG Key ID: 24DA7517711A2BA4
8 changed files with 137 additions and 35 deletions

1
Cargo.lock generated
View File

@ -1260,7 +1260,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/ruma/ruma-federation-api.git#5448c650f0a583382152d0f43f2dcf720d495390"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-api", "ruma-api",

View File

@ -18,7 +18,7 @@ ruma-identifiers = "0.15.1"
ruma-api = "0.16.0-rc.1" ruma-api = "0.16.0-rc.1"
ruma-events = "0.19.0" ruma-events = "0.19.0"
ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git" } 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" pretty_env_logger = "0.4.0"
log = "0.4.8" log = "0.4.8"
sled = "0.31.0" sled = "0.31.0"

View File

@ -1,4 +1,4 @@
use crate::{utils, Data, MatrixResult, Ruma}; use crate::{server_server, utils, Data, MatrixResult, Ruma};
use log::debug; use log::debug;
use rocket::{get, options, post, put, State}; use rocket::{get, options, post, put, State};
@ -674,7 +674,8 @@ pub fn join_room_by_id_or_alias_route(
} }
} }
} else { } else {
body.room_id_or_alias.try_into().unwrap() todo!();
//body.room_id_or_alias.try_into().unwrap()
}; };
if data.room_join( if data.room_join(
@ -725,8 +726,8 @@ pub fn invite_user_route(
} }
#[post("/_matrix/client/r0/publicRooms", data = "<body>")] #[post("/_matrix/client/r0/publicRooms", data = "<body>")]
pub fn get_public_rooms_filtered_route( pub async fn get_public_rooms_filtered_route(
data: State<Data>, data: State<'_, Data>,
body: Ruma<get_public_rooms_filtered::Request>, body: Ruma<get_public_rooms_filtered::Request>,
) -> MatrixResult<get_public_rooms_filtered::Response> { ) -> MatrixResult<get_public_rooms_filtered::Response> {
let mut chunk = data let mut chunk = data
@ -752,6 +753,25 @@ pub fn get_public_rooms_filtered_route(
}) })
.collect::<Vec<_>>(); .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)); chunk.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members));
let total_room_count_estimate = (chunk.len() as u32).into(); let total_room_count_estimate = (chunk.len() as u32).into();

View File

@ -457,7 +457,7 @@ impl Data {
)) ))
.expect("ruma's reference hashes are correct"); .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); ruma_signatures::hash_and_sign_event(self.hostname(), self.keypair(), &mut pdu_json);
self.pdu_leaves_replace(&room_id, &pdu.event_id); self.pdu_leaves_replace(&room_id, &pdu.event_id);
@ -483,7 +483,7 @@ impl Data {
self.db self.db
.pduid_pdu .pduid_pdu
.insert(&pdu_id, &*serde_json::to_string(&pdu_json).unwrap()) .insert(&pdu_id, &*pdu_json.to_string())
.unwrap(); .unwrap();
self.db self.db
@ -497,7 +497,10 @@ impl Data {
key.extend_from_slice(pdu.kind.to_string().as_bytes()); key.extend_from_slice(pdu.kind.to_string().as_bytes());
key.push(0xff); key.push(0xff);
key.extend_from_slice(state_key.to_string().as_bytes()); 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 pdu.event_id

View File

@ -127,7 +127,7 @@ impl Database {
&*db.update_and_fetch("keypair", utils::generate_keypair) &*db.update_and_fetch("keypair", utils::generate_keypair)
.unwrap() .unwrap()
.unwrap(), .unwrap(),
"0.0.0".to_owned(), "key1".to_owned(),
) )
.unwrap(), .unwrap(),
_db: db, _db: db,

View File

@ -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, data: &crate::Data,
method: http::Method,
uri: String,
destination: String, destination: String,
request: T, 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, T::Error: std::fmt::Debug,
{ {
let mut http_request: http::Request<_> = request.try_into().unwrap(); 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(); let request_map = request_json.as_object_mut().unwrap();
request_map.insert("method".to_owned(), method.to_string().into()); request_map.insert("method".to_owned(), T::METADATA.method.to_string().into());
request_map.insert("uri".to_owned(), uri.to_string().into()); request_map.insert("uri".to_owned(), uri.into());
//TODO: request_map.insert("origin".to_owned(), data.origin().to_string().into()); request_map.insert("origin".to_owned(), data.hostname().into());
request_map.insert("destination".to_owned(), destination.to_string().into()); request_map.insert("destination".to_owned(), destination.to_string().into());
ruma_signatures::sign_json(data.hostname(), data.keypair(), &mut request_json).unwrap(); ruma_signatures::sign_json(data.hostname(), data.keypair(), dbg!(&mut request_json)).unwrap();
let signature = request_json["signatures"]; let signatures = request_json["signatures"]
data.reqwest_client().execute(http_request.into()); .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
}
}
} }

View File

@ -1,8 +1,7 @@
use super::*; use super::*;
use rocket::{local::Client, http::Status}; use rocket::{http::Status, local::Client};
use serde_json::Value;
use serde_json::json;
use ruma_client_api::error::ErrorKind; use ruma_client_api::error::ErrorKind;
use serde_json::{json, Value};
use std::time::Duration; use std::time::Duration;
fn setup_client() -> Client { fn setup_client() -> Client {
@ -19,7 +18,8 @@ async fn register_login() {
let mut response = client let mut response = client
.post("/_matrix/client/r0/register?kind=user") .post("/_matrix/client/r0/register?kind=user")
.body(registration_init()) .body(registration_init())
.dispatch().await; .dispatch()
.await;
let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap();
assert_eq!(response.status().code, 401); assert_eq!(response.status().code, 401);
@ -33,14 +33,16 @@ async fn login_after_register_correct_password() {
let mut response = client let mut response = client
.post("/_matrix/client/r0/register?kind=user") .post("/_matrix/client/r0/register?kind=user")
.body(registration_init()) .body(registration_init())
.dispatch().await; .dispatch()
.await;
let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap();
let session = body["session"].clone(); let session = body["session"].clone();
let response = client let response = client
.post("/_matrix/client/r0/register?kind=user") .post("/_matrix/client/r0/register?kind=user")
.body(registration(session.as_str().unwrap())) .body(registration(session.as_str().unwrap()))
.dispatch().await; .dispatch()
.await;
assert_eq!(response.status().code, 200); assert_eq!(response.status().code, 200);
let login_response = client let login_response = client
@ -57,14 +59,16 @@ async fn login_after_register_incorrect_password() {
let mut response = client let mut response = client
.post("/_matrix/client/r0/register?kind=user") .post("/_matrix/client/r0/register?kind=user")
.body(registration_init()) .body(registration_init())
.dispatch().await; .dispatch()
.await;
let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap(); let body = serde_json::from_str::<Value>(&response.body_string().await.unwrap()).unwrap();
let session = body["session"].clone(); let session = body["session"].clone();
let response = client let response = client
.post("/_matrix/client/r0/register?kind=user") .post("/_matrix/client/r0/register?kind=user")
.body(registration(session.as_str().unwrap())) .body(registration(session.as_str().unwrap()))
.dispatch().await; .dispatch()
.await;
assert_eq!(response.status().code, 200); assert_eq!(response.status().code, 200);
let mut login_response = client let mut login_response = client
@ -73,7 +77,15 @@ async fn login_after_register_incorrect_password() {
.dispatch() .dispatch()
.await; .await;
let body = serde_json::from_str::<Value>(&login_response.body_string().await.unwrap()).unwrap(); 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); assert_eq!(login_response.status().code, 403);
} }
@ -98,7 +110,8 @@ fn registration(session: &str) -> String {
"device_id": "GHTYAJCE", "device_id": "GHTYAJCE",
"initial_device_display_name": "Jungle Phone", "initial_device_display_name": "Jungle Phone",
"inhibit_login": false "inhibit_login": false
}).to_string() })
.to_string()
} }
fn login_with_password(password: &str) -> String { fn login_with_password(password: &str) -> String {
@ -110,5 +123,6 @@ fn login_with_password(password: &str) -> String {
}, },
"password": password, "password": password,
"initial_device_display_name": "Jungle Phone" "initial_device_display_name": "Jungle Phone"
}).to_string() })
.to_string()
} }

View File

@ -27,8 +27,10 @@ pub fn increment(old: Option<&[u8]>) -> Option<Vec<u8>> {
pub fn generate_keypair(old: Option<&[u8]>) -> Option<Vec<u8>> { pub fn generate_keypair(old: Option<&[u8]>) -> Option<Vec<u8>> {
Some( Some(
/*
old.map(|s| s.to_vec()) old.map(|s| s.to_vec())
.unwrap_or_else(|| ruma_signatures::Ed25519KeyPair::generate().unwrap()), .unwrap_or_else(|| */
ruma_signatures::Ed25519KeyPair::generate().unwrap(),
) )
} }