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:
parent
d82ea331cf
commit
c0939c3e9a
30 changed files with 1025 additions and 1378 deletions
|
@ -1,16 +1,9 @@
|
|||
use std::{
|
||||
collections::BTreeMap,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use conduit::{trace, utils, utils::rand, Error, Result, Server};
|
||||
use database::{Database, Deserialized, Json, Map};
|
||||
use conduit::{trace, utils, Result, Server};
|
||||
use database::{Database, Deserialized, Map};
|
||||
use futures::{pin_mut, stream::FuturesUnordered, FutureExt, StreamExt};
|
||||
use ruma::{
|
||||
api::federation::discovery::{ServerSigningKeys, VerifyKey},
|
||||
signatures::Ed25519KeyPair,
|
||||
DeviceId, MilliSecondsSinceUnixEpoch, OwnedServerSigningKeyId, ServerName, UserId,
|
||||
};
|
||||
use ruma::{DeviceId, UserId};
|
||||
|
||||
use crate::{rooms, Dep};
|
||||
|
||||
|
@ -25,7 +18,6 @@ pub struct Data {
|
|||
pduid_pdu: Arc<Map>,
|
||||
keychangeid_userid: Arc<Map>,
|
||||
roomusertype_roomuserdataid: Arc<Map>,
|
||||
server_signingkeys: Arc<Map>,
|
||||
readreceiptid_readreceipt: Arc<Map>,
|
||||
userid_lastonetimekeyupdate: Arc<Map>,
|
||||
counter: RwLock<u64>,
|
||||
|
@ -56,7 +48,6 @@ impl Data {
|
|||
pduid_pdu: db["pduid_pdu"].clone(),
|
||||
keychangeid_userid: db["keychangeid_userid"].clone(),
|
||||
roomusertype_roomuserdataid: db["roomusertype_roomuserdataid"].clone(),
|
||||
server_signingkeys: db["server_signingkeys"].clone(),
|
||||
readreceiptid_readreceipt: db["readreceiptid_readreceipt"].clone(),
|
||||
userid_lastonetimekeyupdate: db["userid_lastonetimekeyupdate"].clone(),
|
||||
counter: RwLock::new(Self::stored_count(&db["global"]).expect("initialized global counter")),
|
||||
|
@ -205,107 +196,6 @@ impl Data {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_keypair(&self) -> Result<Ed25519KeyPair> {
|
||||
let generate = |_| {
|
||||
let keypair = Ed25519KeyPair::generate().expect("Ed25519KeyPair generation always works (?)");
|
||||
|
||||
let mut value = rand::string(8).as_bytes().to_vec();
|
||||
value.push(0xFF);
|
||||
value.extend_from_slice(&keypair);
|
||||
|
||||
self.global.insert(b"keypair", &value);
|
||||
value
|
||||
};
|
||||
|
||||
let keypair_bytes: Vec<u8> = self
|
||||
.global
|
||||
.get_blocking(b"keypair")
|
||||
.map_or_else(generate, Into::into);
|
||||
|
||||
let mut parts = keypair_bytes.splitn(2, |&b| b == 0xFF);
|
||||
utils::string_from_bytes(
|
||||
// 1. version
|
||||
parts
|
||||
.next()
|
||||
.expect("splitn always returns at least one element"),
|
||||
)
|
||||
.map_err(|_| Error::bad_database("Invalid version bytes in keypair."))
|
||||
.and_then(|version| {
|
||||
// 2. key
|
||||
parts
|
||||
.next()
|
||||
.ok_or_else(|| Error::bad_database("Invalid keypair format in database."))
|
||||
.map(|key| (version, key))
|
||||
})
|
||||
.and_then(|(version, key)| {
|
||||
Ed25519KeyPair::from_der(key, version)
|
||||
.map_err(|_| Error::bad_database("Private or public keys are invalid."))
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remove_keypair(&self) -> Result<()> {
|
||||
self.global.remove(b"keypair");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// TODO: the key valid until timestamp (`valid_until_ts`) is only honored
|
||||
/// in room version > 4
|
||||
///
|
||||
/// Remove the outdated keys and insert the new ones.
|
||||
///
|
||||
/// This doesn't actually check that the keys provided are newer than the
|
||||
/// old set.
|
||||
pub async fn add_signing_key(
|
||||
&self, origin: &ServerName, new_keys: ServerSigningKeys,
|
||||
) -> BTreeMap<OwnedServerSigningKeyId, VerifyKey> {
|
||||
// (timo) Not atomic, but this is not critical
|
||||
let mut keys: ServerSigningKeys = self
|
||||
.server_signingkeys
|
||||
.get(origin)
|
||||
.await
|
||||
.deserialized()
|
||||
.unwrap_or_else(|_| {
|
||||
// Just insert "now", it doesn't matter
|
||||
ServerSigningKeys::new(origin.to_owned(), MilliSecondsSinceUnixEpoch::now())
|
||||
});
|
||||
|
||||
keys.verify_keys.extend(new_keys.verify_keys);
|
||||
keys.old_verify_keys.extend(new_keys.old_verify_keys);
|
||||
|
||||
self.server_signingkeys.raw_put(origin, Json(&keys));
|
||||
|
||||
let mut tree = keys.verify_keys;
|
||||
tree.extend(
|
||||
keys.old_verify_keys
|
||||
.into_iter()
|
||||
.map(|old| (old.0, VerifyKey::new(old.1.key))),
|
||||
);
|
||||
|
||||
tree
|
||||
}
|
||||
|
||||
/// This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
|
||||
/// for the server.
|
||||
pub async fn verify_keys_for(&self, origin: &ServerName) -> Result<BTreeMap<OwnedServerSigningKeyId, VerifyKey>> {
|
||||
self.signing_keys_for(origin).await.map_or_else(
|
||||
|_| Ok(BTreeMap::new()),
|
||||
|keys: ServerSigningKeys| {
|
||||
let mut tree = keys.verify_keys;
|
||||
tree.extend(
|
||||
keys.old_verify_keys
|
||||
.into_iter()
|
||||
.map(|old| (old.0, VerifyKey::new(old.1.key))),
|
||||
);
|
||||
Ok(tree)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn signing_keys_for(&self, origin: &ServerName) -> Result<ServerSigningKeys> {
|
||||
self.server_signingkeys.get(origin).await.deserialized()
|
||||
}
|
||||
|
||||
pub async fn database_version(&self) -> u64 {
|
||||
self.global
|
||||
.get(b"version")
|
||||
|
|
|
@ -2,7 +2,7 @@ mod data;
|
|||
pub(super) mod migrations;
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
collections::HashMap,
|
||||
fmt::Write,
|
||||
sync::{Arc, RwLock},
|
||||
time::Instant,
|
||||
|
@ -13,13 +13,8 @@ use data::Data;
|
|||
use ipaddress::IPAddress;
|
||||
use regex::RegexSet;
|
||||
use ruma::{
|
||||
api::{
|
||||
client::discovery::discover_support::ContactRole,
|
||||
federation::discovery::{ServerSigningKeys, VerifyKey},
|
||||
},
|
||||
serde::Base64,
|
||||
DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, RoomAliasId,
|
||||
RoomVersionId, ServerName, UserId,
|
||||
api::client::discovery::discover_support::ContactRole, DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedServerName,
|
||||
OwnedUserId, RoomAliasId, RoomVersionId, ServerName, UserId,
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
use url::Url;
|
||||
|
@ -31,7 +26,6 @@ pub struct Service {
|
|||
|
||||
pub config: Config,
|
||||
pub cidr_range_denylist: Vec<IPAddress>,
|
||||
keypair: Arc<ruma::signatures::Ed25519KeyPair>,
|
||||
jwt_decoding_key: Option<jsonwebtoken::DecodingKey>,
|
||||
pub stable_room_versions: Vec<RoomVersionId>,
|
||||
pub unstable_room_versions: Vec<RoomVersionId>,
|
||||
|
@ -50,16 +44,6 @@ impl crate::Service for Service {
|
|||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
let db = Data::new(&args);
|
||||
let config = &args.server.config;
|
||||
let keypair = db.load_keypair();
|
||||
|
||||
let keypair = match keypair {
|
||||
Ok(k) => k,
|
||||
Err(e) => {
|
||||
error!("Keypair invalid. Deleting...");
|
||||
db.remove_keypair()?;
|
||||
return Err(e);
|
||||
},
|
||||
};
|
||||
|
||||
let jwt_decoding_key = config
|
||||
.jwt_secret
|
||||
|
@ -115,7 +99,6 @@ impl crate::Service for Service {
|
|||
db,
|
||||
config: config.clone(),
|
||||
cidr_range_denylist,
|
||||
keypair: Arc::new(keypair),
|
||||
jwt_decoding_key,
|
||||
stable_room_versions,
|
||||
unstable_room_versions,
|
||||
|
@ -175,9 +158,6 @@ impl crate::Service for Service {
|
|||
}
|
||||
|
||||
impl Service {
|
||||
/// Returns this server's keypair.
|
||||
pub fn keypair(&self) -> &ruma::signatures::Ed25519KeyPair { &self.keypair }
|
||||
|
||||
#[inline]
|
||||
pub fn next_count(&self) -> Result<u64> { self.db.next_count() }
|
||||
|
||||
|
@ -224,8 +204,6 @@ impl Service {
|
|||
|
||||
pub fn trusted_servers(&self) -> &[OwnedServerName] { &self.config.trusted_servers }
|
||||
|
||||
pub fn query_trusted_key_servers_first(&self) -> bool { self.config.query_trusted_key_servers_first }
|
||||
|
||||
pub fn jwt_decoding_key(&self) -> Option<&jsonwebtoken::DecodingKey> { self.jwt_decoding_key.as_ref() }
|
||||
|
||||
pub fn turn_password(&self) -> &String { &self.config.turn_password }
|
||||
|
@ -302,28 +280,6 @@ impl Service {
|
|||
}
|
||||
}
|
||||
|
||||
/// This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
|
||||
/// for the server.
|
||||
pub async fn verify_keys_for(&self, origin: &ServerName) -> Result<BTreeMap<OwnedServerSigningKeyId, VerifyKey>> {
|
||||
let mut keys = self.db.verify_keys_for(origin).await?;
|
||||
if origin == self.server_name() {
|
||||
keys.insert(
|
||||
format!("ed25519:{}", self.keypair().version())
|
||||
.try_into()
|
||||
.expect("found invalid server signing keys in DB"),
|
||||
VerifyKey {
|
||||
key: Base64::new(self.keypair.public_key().to_vec()),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
pub async fn signing_keys_for(&self, origin: &ServerName) -> Result<ServerSigningKeys> {
|
||||
self.db.signing_keys_for(origin).await
|
||||
}
|
||||
|
||||
pub fn well_known_client(&self) -> &Option<Url> { &self.config.well_known.client }
|
||||
|
||||
pub fn well_known_server(&self) -> &Option<OwnedServerName> { &self.config.well_known.server }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue