Step 5 in /send just fetches state from incoming server

This commit is contained in:
Devin Ragotzy 2021-01-03 17:26:17 -05:00 committed by Timo Kösters
parent 9e83d2b2d5
commit 0ee239c9d7
No known key found for this signature in database
GPG key ID: 24DA7517711A2BA4
4 changed files with 186 additions and 187 deletions

78
Cargo.lock generated
View file

@ -2,9 +2,9 @@
# It is not intended for manual editing.
[[package]]
name = "addr2line"
version = "0.14.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"
checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
dependencies = [
"gimli",
]
@ -44,9 +44,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "assign"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4af5687fe33aec5e70ef14caac5e0d363e335e5e5d6385fb75978d0c241b1d67"
checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002"
[[package]]
name = "async-trait"
@ -354,9 +354,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "dtoa"
version = "0.4.6"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
[[package]]
name = "either"
@ -561,11 +561,11 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.1.15"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"libc",
"wasi",
]
@ -819,9 +819,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "0.4.6"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "jpeg-decoder"
@ -1017,9 +1017,9 @@ dependencies = [
[[package]]
name = "native-tls"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fcc7939b5edc4e4f86b1b4a04bb1498afaaf871b1a6691838ed06fcb48d3a3f"
checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
dependencies = [
"lazy_static",
"libc",
@ -1109,9 +1109,9 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "openssl"
version = "0.10.31"
version = "0.10.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d008f51b1acffa0d3450a68606e6a51c123012edaacb0f4e1426bd978869187"
checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
@ -1138,9 +1138,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.59"
version = "0.9.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de52d8eabd217311538a39bba130d7dea1f1e118010fee7a033d966845e7d5fe"
checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6"
dependencies = [
"autocfg",
"cc",
@ -1356,7 +1356,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.15",
"getrandom 0.1.16",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
@ -1401,7 +1401,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.15",
"getrandom 0.1.16",
]
[[package]]
@ -1443,25 +1443,25 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
"getrandom 0.1.15",
"getrandom 0.1.16",
"redox_syscall",
"rust-argon2",
]
[[package]]
name = "ref-cast"
version = "1.0.3"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17626b2f4bcf35b84bf379072a66e28cfe5c3c6ae58b38e4914bb8891dabece"
checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.3"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c523ccaed8ac4b0288948849a350b37d3035827413c458b6a40ddb614bb4f72"
checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2"
dependencies = [
"proc-macro2",
"quote",
@ -1954,9 +1954,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.60"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [
"itoa",
"ryu",
@ -2026,9 +2026,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0"
[[package]]
name = "socket2"
@ -2049,9 +2049,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "standback"
version = "0.2.13"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf906c8b8fc3f6ecd1046e01da1d8ddec83e48c8b08b84dcc02b585a6bedf5a8"
checksum = "c66a8cff4fa24853fdf6b51f75c6d7f8206d7c75cab4e467bcd7f25c2b1febe0"
dependencies = [
"version_check",
]
@ -2065,7 +2065,7 @@ checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483"
[[package]]
name = "state-res"
version = "0.1.0"
source = "git+https://github.com/ruma/state-res?branch=event-trait#9b96204571521e216a618d102459d662c52a2210"
source = "git+https://github.com/ruma/state-res?branch=event-trait#bfadbdf57e26f26c2ea5b2ed50ce3e5f6fb914cd"
dependencies = [
"itertools",
"maplit",
@ -2127,9 +2127,9 @@ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
[[package]]
name = "syn"
version = "1.0.55"
version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a"
checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6"
dependencies = [
"proc-macro2",
"quote",
@ -2152,18 +2152,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.22"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e"
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.22"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56"
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
dependencies = [
"proc-macro2",
"quote",
@ -2673,9 +2673,9 @@ dependencies = [
[[package]]
name = "yaml-rust"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View file

@ -802,32 +802,9 @@ impl Rooms {
))?)?
.map(Arc::new);
event_auth::valid_membership_change(
// TODO this is a bit of a hack but not sure how to have a type
// declared in `state_res` crate easily convert to/from conduit::PduEvent
&Arc::new(PduEvent {
event_id: ruma::event_id!("$thiswillbefilledinlater"),
room_id: room_id.clone(),
sender: sender.clone(),
origin_server_ts: utils::millis_since_unix_epoch()
.try_into()
.expect("time is valid"),
kind: event_type,
content,
state_key: Some(state_key.clone()),
prev_events,
depth: (prev_events.len() as u32).into(),
auth_events: auth_events
.into_iter()
.map(|(_, pdu)| pdu.event_id)
.collect(),
redacts,
unsigned: unsigned
.map_or_else(BTreeMap::new, |m| m.into_iter().collect()),
hashes: ruma::events::pdu::EventHash {
sha256: "aaa".to_owned(),
},
signatures: BTreeMap::new(),
}),
Some(state_key.as_str()),
&sender,
content.clone(),
prev_event,
None, // TODO: third party invite
&auth_events

View file

@ -229,7 +229,7 @@ impl PduEvent {
pub fn from_id_val(
event_id: &EventId,
json: CanonicalJsonObject,
mut json: CanonicalJsonObject,
) -> Result<Self, serde_json::Error> {
json.insert(
"event_id".to_string(),

View file

@ -1,4 +1,4 @@
use crate::{client_server, utils, ConduitResult, Database, Error, PduEvent, Result, Ruma};
use crate::{client_server, pdu, utils, ConduitResult, Database, Error, PduEvent, Result, Ruma};
use get_profile_information::v1::ProfileField;
use http::header::{HeaderValue, AUTHORIZATION, HOST};
use log::{error, info, warn};
@ -11,13 +11,15 @@ use ruma::{
get_server_keys, get_server_version::v1 as get_server_version, ServerSigningKeys,
VerifyKey,
},
event::{get_missing_events, get_room_state, get_room_state_ids},
event::{get_event, get_missing_events, get_room_state, get_room_state_ids},
query::get_profile_information,
transactions::send_transaction_message,
},
OutgoingRequest,
},
directory::{IncomingFilter, IncomingRoomNetwork},
serde::Raw,
signatures::{CanonicalJsonObject, PublicKeyMap},
EventId, RoomId, RoomVersionId, ServerName, ServerSigningKeyId, UserId,
};
use state_res::{Event, StateMap};
@ -578,32 +580,13 @@ pub async fn send_transaction_message_route<'a>(
let mut pub_key_map = BTreeMap::new();
pub_key_map.insert("domain".to_string(), pub_key_set);
let value =
match ruma::signatures::verify_event(&pub_key_map, &value, &RoomVersionId::Version6) {
Ok(ver) => {
if let ruma::signatures::Verified::Signatures = ver {
match ruma::signatures::redact(&value, &RoomVersionId::Version6) {
Ok(obj) => obj,
Err(_) => {
resolved_map
.insert(event_id, Err("Room is unknown to this server".into()));
continue;
}
}
} else {
value
}
}
Err(_e) => {
resolved_map.insert(event_id, Err("Room is unknown to this server".into()));
continue;
}
};
let pdu = serde_json::from_value::<PduEvent>(
serde_json::to_value(&value).expect("CanonicalJsonObj is a valid JsonValue"),
)
.expect("all ruma pdus are conduit pdus");
let pdu = match signature_and_hash_check(&pub_key_map, value) {
Ok(pdu) => pdu,
Err(e) => {
resolved_map.insert(event_id, Err(e));
continue;
}
};
// If we have no idea about this room skip the PDU
if !db.rooms.exists(&pdu.room_id)? {
@ -619,7 +602,10 @@ pub async fn send_transaction_message_route<'a>(
.map(|id| db.rooms.get_pdu(id).expect("todo").map(Arc::new))
.flatten();
// 4.
// 4. Passes authorization rules based on the event's auth events, otherwise it is rejected.
// TODO: To me this sounds more like the auth_events should be get the pdu.auth_events not
// the auth events that would be correct for this pdu. Put another way we should use the auth events
// the pdu claims are its auth events
let auth_events = db.rooms.get_auth_events(
&pdu.room_id,
&pdu.kind,
@ -627,6 +613,12 @@ pub async fn send_transaction_message_route<'a>(
pdu.state_key.as_deref(),
pdu.content.clone(),
)?;
let mut event_map: state_res::EventMap<Arc<PduEvent>> = auth_events
.iter()
.map(|(k, v)| (v.event_id().clone(), Arc::new(v.clone())))
.collect();
if !state_res::event_auth::auth_check(
&RoomVersionId::Version6,
&event,
@ -635,7 +627,7 @@ pub async fn send_transaction_message_route<'a>(
.into_iter()
.map(|(k, v)| (k, Arc::new(v)))
.collect(),
None,
None, // TODO: third party invite
)
.map_err(|_e| Error::Conflict("Auth check failed"))?
{
@ -646,66 +638,38 @@ pub async fn send_transaction_message_route<'a>(
continue;
}
let mut previous_states: Vec<StateMap<Arc<PduEvent>>> = vec![];
for id in &pdu.prev_events {
if let Some(id) = db.rooms.get_pdu_id(id)? {
let state_hash = db
.rooms
.pdu_state_hash(&id)?
.expect("found pdu with no statehash");
let state = db
.rooms
.state_full(&pdu.room_id, &state_hash)?
let server_name = body.body.origin.clone();
let (state_at_event, incoming_auth_events): (StateMap<Arc<PduEvent>>, _) = match db
.sending
.send_federation_request(
&db.globals,
server_name.clone(),
get_room_state_ids::v1::Request {
room_id: pdu.room_id(),
event_id: pdu.event_id(),
},
)
.await
{
Ok(res) => {
let state = fetch_events(&db, server_name.clone(), &pub_key_map, &res.pdu_ids)
.await?
.into_iter()
.map(|((et, sk), ev)| ((et, Some(sk)), Arc::new(ev)))
.map(|pdu| ((pdu.kind.clone(), pdu.state_key.clone()), Arc::new(pdu)))
.collect();
previous_states.push(state);
} else {
// fetch the state
match db
.sending
.send_federation_request(
&db.globals,
body.body.origin,
get_room_state_ids::v1::Request {
room_id: &pdu.room_id,
event_id: id,
},
)
.await
{
Ok(res) => todo!(),
Err(e) => panic!(e),
}
}
}
// 5. Passes authorization rules based on the state at the event, otherwise it is rejected.
let state_at_event = if previous_states.is_empty() {
// State is empty
Default::default()
} else if previous_states.len() == 1 {
previous_states[0].clone()
} else {
match state_res::StateResolution::resolve(
&pdu.room_id,
&RoomVersionId::Version6,
&previous_states
.into_iter()
.map(|map| {
map.into_iter()
.map(|(k, v)| (k, v.event_id.clone()))
.collect::<StateMap<_>>()
})
.collect::<Vec<_>>(),
None,
&db.rooms,
) {
Ok(res) => res
.into_iter()
.map(|(k, v)| (k, Arc::new(db.rooms.get_pdu(&v).unwrap().unwrap())))
.collect(),
Err(e) => panic!("{:?}", e),
(
state,
fetch_events(&db, server_name.clone(), &pub_key_map, &res.auth_chain_ids)
.await?,
)
}
Err(_) => {
resolved_map.insert(
event.event_id().clone(),
Err("Fetching state for event failed".into()),
);
continue;
}
};
@ -713,8 +677,8 @@ pub async fn send_transaction_message_route<'a>(
&RoomVersionId::Version6,
&event,
previous.clone(),
state_at_event,
None,
state_at_event.clone(), // TODO: could this be &state avoid .clone
None, // TODO: third party invite
)
.map_err(|_e| Error::Conflict("Auth check failed"))?
{
@ -747,22 +711,7 @@ pub async fn send_transaction_message_route<'a>(
fork_states.push(state);
} else {
// This is probably an error??
match db
.sending
.send_federation_request(
&db.globals,
body.body.origin,
get_room_state_ids::v1::Request {
room_id: &pdu.room_id,
event_id: id,
},
)
.await
{
Ok(res) => todo!(),
Err(e) => panic!(e),
}
todo!("we don't know of a pdu that is part of our known forks OOPS")
}
}
@ -773,6 +722,18 @@ pub async fn send_transaction_message_route<'a>(
} else if fork_states.len() == 1 {
fork_states[0].clone()
} else {
// Add as much as we can to the `event_map` (less DB hits)
event_map.extend(
incoming_auth_events
.into_iter()
.map(|pdu| (pdu.event_id().clone(), Arc::new(pdu))),
);
event_map.extend(
state_at_event
.into_iter()
.map(|(_, pdu)| (pdu.event_id().clone(), pdu)),
);
match state_res::StateResolution::resolve(
&pdu.room_id,
&RoomVersionId::Version6,
@ -784,7 +745,7 @@ pub async fn send_transaction_message_route<'a>(
.collect::<StateMap<_>>()
})
.collect::<Vec<_>>(),
None,
&mut event_map,
&db.rooms,
) {
Ok(res) => res
@ -819,8 +780,74 @@ pub async fn send_transaction_message_route<'a>(
Ok(send_transaction_message::v1::Response { pdus: resolved_map }.into())
}
fn signature_and_hash_check(
pub_key_map: &ruma::signatures::PublicKeyMap,
value: CanonicalJsonObject,
) -> std::result::Result<PduEvent, String> {
let val = match ruma::signatures::verify_event(pub_key_map, &value, &RoomVersionId::Version6) {
Ok(ver) => {
if let ruma::signatures::Verified::Signatures = ver {
match ruma::signatures::redact(&value, &RoomVersionId::Version6) {
Ok(obj) => obj,
Err(_) => return Err("Redaction failed".into()),
}
} else {
value
}
}
Err(_e) => return Err("Signature verification failed".into()),
};
serde_json::from_value::<PduEvent>(
serde_json::to_value(val).expect("CanonicalJsonObj is a valid JsonValue"),
)
.map_err(|_| "Deserialization failed for JSON value".into())
}
/// TODO: this needs to add events to the DB in a way that does not
/// effect the state of the room
async fn fetch_events(
db: &Database,
origin: Box<ServerName>,
key_map: &PublicKeyMap,
events: &[EventId],
) -> Result<Vec<PduEvent>> {
let mut pdus = vec![];
for id in events {
match db.rooms.get_pdu(id)? {
Some(pdu) => pdus.push(pdu),
None => match db
.sending
.send_federation_request(
&db.globals,
origin.clone(),
get_event::v1::Request { event_id: id },
)
.await
{
Ok(res) => {
let (_, value) = crate::pdu::process_incoming_pdu(&res.pdu);
match signature_and_hash_check(key_map, value) {
Ok(pdu) => {
// TODO: add to our DB somehow?
pdus.push(pdu);
}
Err(e) => {
// TODO: I would assume we just keep going
error!("{:?}", e);
continue;
}
}
}
Err(_) => return Err(Error::BadServerResponse("Failed to fetch event")),
},
}
}
Ok(pdus)
}
fn forward_extremity_ids(db: &Database, room_id: &RoomId) -> Result<Vec<EventId>> {
todo!()
db.rooms.get_pdu_leaves(room_id)
}
fn append_state(db: &Database, pdu: &PduEvent) -> Result<()> {
@ -854,20 +881,15 @@ fn append_state_soft(db: &Database, pdu: &PduEvent) -> Result<()> {
pdu_id.push(0xff);
pdu_id.extend_from_slice(&count.to_be_bytes());
db.rooms.append_to_state(&pdu_id, pdu, &db.globals)?;
db.rooms.append_pdu(
pdu,
&utils::to_canonical_object(pdu).expect("Pdu is valid canonical object"),
count,
pdu_id.clone().into(),
&db.globals,
&db.account_data,
&db.admin,
)?;
for appservice in db.appservice.iter_all().filter_map(|r| r.ok()) {
db.sending.send_pdu_appservice(&appservice.0, &pdu_id)?;
}
// db.rooms.append_pdu(
// pdu,
// &utils::to_canonical_object(pdu).expect("Pdu is valid canonical object"),
// count,
// pdu_id.clone().into(),
// &db.globals,
// &db.account_data,
// &db.admin,
// )?;
Ok(())
}