Refactor server_keys service/interface and related callsites

Signed-off-by: Jason Volk <jason@zemos.net>
Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
Jason Volk 2024-10-11 18:57:59 +00:00 committed by strawberry
parent d82ea331cf
commit c0939c3e9a
30 changed files with 1025 additions and 1378 deletions

View file

@ -85,13 +85,10 @@ pub(crate) async fn create_invite_route(
.acl_check(invited_user.server_name(), &body.room_id)
.await?;
ruma::signatures::hash_and_sign_event(
services.globals.server_name().as_str(),
services.globals.keypair(),
&mut signed_event,
&body.room_version,
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Failed to sign event."))?;
services
.server_keys
.hash_and_sign_event(&mut signed_event, &body.room_version)
.map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?;
// Generate event id
let event_id = EventId::parse(format!(

View file

@ -1,20 +1,16 @@
use std::{
collections::BTreeMap,
time::{Duration, SystemTime},
};
use std::{collections::BTreeMap, time::Duration};
use axum::{extract::State, response::IntoResponse, Json};
use conduit::{utils::timepoint_from_now, Result};
use ruma::{
api::{
federation::discovery::{get_server_keys, ServerSigningKeys, VerifyKey},
federation::discovery::{get_server_keys, ServerSigningKeys},
OutgoingResponse,
},
serde::{Base64, Raw},
MilliSecondsSinceUnixEpoch, OwnedServerSigningKeyId,
serde::Raw,
MilliSecondsSinceUnixEpoch,
};
use crate::Result;
/// # `GET /_matrix/key/v2/server`
///
/// Gets the public signing keys of this server.
@ -24,47 +20,33 @@ use crate::Result;
// Response type for this endpoint is Json because we need to calculate a
// signature for the response
pub(crate) async fn get_server_keys_route(State(services): State<crate::State>) -> Result<impl IntoResponse> {
let verify_keys: BTreeMap<OwnedServerSigningKeyId, VerifyKey> = BTreeMap::from([(
format!("ed25519:{}", services.globals.keypair().version())
.try_into()
.expect("found invalid server signing keys in DB"),
VerifyKey {
key: Base64::new(services.globals.keypair().public_key().to_vec()),
},
)]);
let server_name = services.globals.server_name();
let verify_keys = services.server_keys.verify_keys_for(server_name).await;
let server_key = ServerSigningKeys {
verify_keys,
server_name: server_name.to_owned(),
valid_until_ts: valid_until_ts(),
old_verify_keys: BTreeMap::new(),
signatures: BTreeMap::new(),
};
let mut response = serde_json::from_slice(
get_server_keys::v2::Response {
server_key: Raw::new(&ServerSigningKeys {
server_name: services.globals.server_name().to_owned(),
verify_keys,
old_verify_keys: BTreeMap::new(),
signatures: BTreeMap::new(),
valid_until_ts: MilliSecondsSinceUnixEpoch::from_system_time(
SystemTime::now()
.checked_add(Duration::from_secs(86400 * 7))
.expect("valid_until_ts should not get this high"),
)
.expect("time is valid"),
})
.expect("static conversion, no errors"),
}
.try_into_http_response::<Vec<u8>>()
.unwrap()
.body(),
)
.unwrap();
let response = get_server_keys::v2::Response {
server_key: Raw::new(&server_key)?,
}
.try_into_http_response::<Vec<u8>>()?;
ruma::signatures::sign_json(
services.globals.server_name().as_str(),
services.globals.keypair(),
&mut response,
)
.unwrap();
let mut response = serde_json::from_slice(response.body())?;
services.server_keys.sign_json(&mut response)?;
Ok(Json(response))
}
fn valid_until_ts() -> MilliSecondsSinceUnixEpoch {
let dur = Duration::from_secs(86400 * 7);
let timepoint = timepoint_from_now(dur).expect("SystemTime should not overflow");
MilliSecondsSinceUnixEpoch::from_system_time(timepoint).expect("UInt should not overflow")
}
/// # `GET /_matrix/key/v2/server/{keyId}`
///
/// Gets the public signing keys of this server.

View file

@ -21,7 +21,6 @@ use ruma::{
OwnedEventId, ServerName,
};
use serde_json::value::RawValue as RawJsonValue;
use tokio::sync::RwLock;
use crate::{
services::Services,
@ -109,22 +108,6 @@ async fn handle_pdus(
// and hashes checks
}
// We go through all the signatures we see on the PDUs and fetch the
// corresponding signing keys
let pub_key_map = RwLock::new(BTreeMap::new());
if !parsed_pdus.is_empty() {
services
.server_keys
.fetch_required_signing_keys(parsed_pdus.iter().map(|(_event_id, event, _room_id)| event), &pub_key_map)
.await
.unwrap_or_else(|e| warn!("Could not fetch all signatures for PDUs from {origin}: {e:?}"));
debug!(
elapsed = ?txn_start_time.elapsed(),
"Fetched signing keys"
);
}
let mut resolved_map = BTreeMap::new();
for (event_id, value, room_id) in parsed_pdus {
let pdu_start_time = Instant::now();
@ -134,17 +117,18 @@ async fn handle_pdus(
.mutex_federation
.lock(&room_id)
.await;
resolved_map.insert(
event_id.clone(),
services
.rooms
.event_handler
.handle_incoming_pdu(origin, &room_id, &event_id, value, true, &pub_key_map)
.handle_incoming_pdu(origin, &room_id, &event_id, value, true)
.await
.map(|_| ()),
);
drop(mutex_lock);
drop(mutex_lock);
debug!(
pdu_elapsed = ?pdu_start_time.elapsed(),
txn_elapsed = ?txn_start_time.elapsed(),

View file

@ -1,6 +1,6 @@
#![allow(deprecated)]
use std::{borrow::Borrow, collections::BTreeMap};
use std::borrow::Borrow;
use axum::extract::State;
use conduit::{err, pdu::gen_event_id_canonical_json, utils::IterStream, warn, Error, Result};
@ -15,7 +15,6 @@ use ruma::{
};
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use service::Services;
use tokio::sync::RwLock;
use crate::Ruma;
@ -43,9 +42,6 @@ async fn create_join_event(
.await
.map_err(|_| err!(Request(NotFound("Event state not found."))))?;
let pub_key_map = RwLock::new(BTreeMap::new());
// let mut auth_cache = EventMap::new();
// We do not add the event_id field to the pdu here because of signature and
// hashes checks
let room_version_id = services.rooms.state.get_room_version(room_id).await?;
@ -137,20 +133,12 @@ async fn create_join_event(
.await
.unwrap_or_default()
{
ruma::signatures::hash_and_sign_event(
services.globals.server_name().as_str(),
services.globals.keypair(),
&mut value,
&room_version_id,
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Failed to sign event."))?;
services
.server_keys
.hash_and_sign_event(&mut value, &room_version_id)
.map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?;
}
services
.server_keys
.fetch_required_signing_keys([&value], &pub_key_map)
.await?;
let origin: OwnedServerName = serde_json::from_value(
serde_json::to_value(
value
@ -171,7 +159,7 @@ async fn create_join_event(
let pdu_id: Vec<u8> = services
.rooms
.event_handler
.handle_incoming_pdu(&origin, room_id, &event_id, value.clone(), true, &pub_key_map)
.handle_incoming_pdu(&origin, room_id, &event_id, value.clone(), true)
.await?
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Could not accept as timeline event."))?;

View file

@ -1,7 +1,5 @@
#![allow(deprecated)]
use std::collections::BTreeMap;
use axum::extract::State;
use conduit::{utils::ReadyExt, Error, Result};
use ruma::{
@ -13,7 +11,6 @@ use ruma::{
OwnedServerName, OwnedUserId, RoomId, ServerName,
};
use serde_json::value::RawValue as RawJsonValue;
use tokio::sync::RwLock;
use crate::{
service::{pdu::gen_event_id_canonical_json, Services},
@ -60,8 +57,6 @@ async fn create_leave_event(
.acl_check(origin, room_id)
.await?;
let pub_key_map = RwLock::new(BTreeMap::new());
// We do not add the event_id field to the pdu here because of signature and
// hashes checks
let room_version_id = services.rooms.state.get_room_version(room_id).await?;
@ -154,21 +149,17 @@ async fn create_leave_event(
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "origin is not a server name."))?;
services
.server_keys
.fetch_required_signing_keys([&value], &pub_key_map)
.await?;
let mutex_lock = services
.rooms
.event_handler
.mutex_federation
.lock(room_id)
.await;
let pdu_id: Vec<u8> = services
.rooms
.event_handler
.handle_incoming_pdu(&origin, room_id, &event_id, value, true, &pub_key_map)
.handle_incoming_pdu(&origin, room_id, &event_id, value, true)
.await?
.ok_or_else(|| Error::BadRequest(ErrorKind::InvalidParam, "Could not accept as timeline event."))?;