mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-14 04:37:00 +00:00
fix: Don't attempt to contact origins as a notary more than once a minute
This commit is contained in:
1 parent
a5a7905494
commit
39cd151ca3
3 files changed
+38
-8
No files matched your search
@@ -177,10 +177,13 @@ pub(crate) async fn get_remote_server_keys_route(
|
|||||||
body: Ruma<get_remote_server_keys::v2::Request>,
|
body: Ruma<get_remote_server_keys::v2::Request>,
|
||||||
) -> Result<get_remote_server_keys::v2::Response> {
|
) -> Result<get_remote_server_keys::v2::Response> {
|
||||||
let min_valid_ts = body.minimum_valid_until_ts;
|
let min_valid_ts = body.minimum_valid_until_ts;
|
||||||
if let Ok(response) = services
|
if services
|
||||||
.server_keys
|
.server_keys
|
||||||
.origin_request(body.server_name.clone(), min_valid_ts)
|
.notary_may_contact_origin(&body.server_name)
|
||||||
.await
|
&& let Ok(response) = services
|
||||||
|
.server_keys
|
||||||
|
.origin_request(body.server_name.clone(), min_valid_ts)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
return sign_ssk(&services, response, &body.server_name)
|
return sign_ssk(&services, response, &body.server_name)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -5,18 +5,22 @@ mod sign;
|
|||||||
mod util;
|
mod util;
|
||||||
mod verify;
|
mod verify;
|
||||||
|
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
sync::Arc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Result, Server,
|
Result, Server, SyncRwLock,
|
||||||
utils::{IterStream, ReadyExt, stream::TryIgnore},
|
utils::{IterStream, ReadyExt, stream::TryIgnore},
|
||||||
};
|
};
|
||||||
use database::{Deserialized, Ignore, Interfix, Json, Map};
|
use database::{Deserialized, Ignore, Interfix, Json, Map};
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
pub use request::in_one_week;
|
pub use request::in_one_week;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
CanonicalJsonObject, MilliSecondsSinceUnixEpoch, OwnedServerSigningKeyId, ServerName,
|
CanonicalJsonObject, MilliSecondsSinceUnixEpoch, OwnedServerName, OwnedServerSigningKeyId,
|
||||||
ServerSigningKeyId,
|
ServerName, ServerSigningKeyId,
|
||||||
api::federation::discovery::{ServerSigningKeys, VerifyKey},
|
api::federation::discovery::{ServerSigningKeys, VerifyKey},
|
||||||
room_version_rules::RoomVersionRules,
|
room_version_rules::RoomVersionRules,
|
||||||
signatures::{Ed25519KeyPair, PublicKeyMap, PublicKeySet},
|
signatures::{Ed25519KeyPair, PublicKeyMap, PublicKeySet},
|
||||||
@@ -30,6 +34,7 @@ pub struct Service {
|
|||||||
verify_keys: VerifyKeys,
|
verify_keys: VerifyKeys,
|
||||||
services: Services,
|
services: Services,
|
||||||
db: Data,
|
db: Data,
|
||||||
|
last_lookup: SyncRwLock<HashMap<OwnedServerName, Instant>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Services {
|
struct Services {
|
||||||
@@ -62,6 +67,7 @@ impl crate::Service for Service {
|
|||||||
db: Data {
|
db: Data {
|
||||||
servernamekeyid_response: args.db["servernamekeyid_response"].clone(),
|
servernamekeyid_response: args.db["servernamekeyid_response"].clone(),
|
||||||
},
|
},
|
||||||
|
last_lookup: SyncRwLock::new(HashMap::new()),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,4 +200,15 @@ impl Service {
|
|||||||
.ignore_err()
|
.ignore_err()
|
||||||
.map(|(_, v): (Ignore, ServerSigningKeys)| v)
|
.map(|(_, v): (Ignore, ServerSigningKeys)| v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines if the server may contact the origin server to fetch keys
|
||||||
|
/// when acting as a notary server. This limits origin lookups to once per
|
||||||
|
/// minute, which prevents amplification attacks.
|
||||||
|
#[must_use]
|
||||||
|
pub fn notary_may_contact_origin(&self, server_name: &ServerName) -> bool {
|
||||||
|
self.last_lookup
|
||||||
|
.read()
|
||||||
|
.get(server_name)
|
||||||
|
.is_none_or(|last| last.elapsed() >= Duration::from_mins(1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::{collections::BTreeMap, time::Instant};
|
||||||
|
|
||||||
use conduwuit::{Err, Result, trace, utils::millis_since_unix_epoch, warn};
|
use conduwuit::{Err, Result, trace, utils::millis_since_unix_epoch, warn};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
@@ -30,6 +30,16 @@ impl super::Service {
|
|||||||
) -> Result<ServerSigningKeys> {
|
) -> Result<ServerSigningKeys> {
|
||||||
use get_server_keys::v2::Request;
|
use get_server_keys::v2::Request;
|
||||||
|
|
||||||
|
// N.B. The "last lookup" is written before the request is actually made
|
||||||
|
// to prevent concurrent notary requests from spawning... concurrent
|
||||||
|
// origin requests, especially if the origin is slow.
|
||||||
|
// This has the downside that, if the origin is temporarily unreachable
|
||||||
|
// (including if we're backing off from it), the notary might take an
|
||||||
|
// additional minute to recover compared to the rest of the server. This
|
||||||
|
// is deemed acceptable.
|
||||||
|
self.last_lookup
|
||||||
|
.write()
|
||||||
|
.insert(target.clone(), Instant::now());
|
||||||
let server_signing_key = self
|
let server_signing_key = self
|
||||||
.services
|
.services
|
||||||
.sending
|
.sending
|
||||||
|
|||||||
Reference in new issue
Block a user