mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-12 19:56:48 +00:00
fix: Avoid v12 room ID collisions when creating rooms concurrently
Fixes #2424. v12 rooms created by the same user in the same millisecond got the same room ID, so they ended up as one room. Reviewed-on: https://forgejo.ellis.link/continuwuation/continuwuity/pulls/2433 Reviewed-by: nex <me@nexy7574.co.uk> Reviewed-by: Jade Ellis <jade@ellis.link>
This commit is contained in:
1 parent
0e5baa9399
commit
0727d564a2
2 files changed
+21
-4
No files matched your search
@@ -0,0 +1 @@
|
||||
Fix v12 rooms created by the same user in the same millisecond ending up as the same room. Contributed by @eleboucher.
|
||||
@@ -1,18 +1,21 @@
|
||||
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashSet},
|
||||
sync::atomic::{AtomicU64, Ordering::SeqCst},
|
||||
};
|
||||
|
||||
use axum::extract::State;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, debug, debug_info, err, info,
|
||||
matrix::{StateKey, pdu::PartialPdu},
|
||||
trace,
|
||||
utils::to_canonical_object,
|
||||
utils::{self, to_canonical_object},
|
||||
warn,
|
||||
};
|
||||
use conduwuit_service::{Services, appservice::RegistrationInfo};
|
||||
use futures::FutureExt;
|
||||
use ruma::{
|
||||
CanonicalJsonObject, CanonicalJsonValue, Int, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId,
|
||||
OwnedUserId, RoomAliasId, RoomId,
|
||||
OwnedUserId, RoomAliasId, RoomId, UInt,
|
||||
api::{
|
||||
client::room::{
|
||||
self,
|
||||
@@ -46,6 +49,8 @@ use serde_json::value::to_raw_value;
|
||||
|
||||
use crate::{Ruma, client::invite_helper};
|
||||
|
||||
static LAST_CREATE_TS: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
// We use this to keep around extra data in the `creation_content`
|
||||
// while still parsing and validating keys that we care about.
|
||||
#[derive(Deserialize, Default)]
|
||||
@@ -307,6 +312,17 @@ pub(crate) async fn create_room_route(
|
||||
.map(MilliSecondsSinceUnixEpoch)
|
||||
};
|
||||
|
||||
// v12+ room IDs are the create event's hash, so give each create event a
|
||||
// unique timestamp to avoid collisions.
|
||||
let create_timestamp = custom_origin_server_ts.or_else(|| {
|
||||
room_id.is_none().then(|| {
|
||||
let now = utils::millis_since_unix_epoch();
|
||||
let next = |last: u64| now.max(last.saturating_add(1));
|
||||
let prev = LAST_CREATE_TS.update(SeqCst, SeqCst, next);
|
||||
MilliSecondsSinceUnixEpoch(UInt::new_saturating(next(prev)))
|
||||
})
|
||||
});
|
||||
|
||||
let mut create_event_content = to_canonical_object(create_event_content)
|
||||
.expect("should be able to serialize create event content");
|
||||
|
||||
@@ -322,7 +338,7 @@ pub(crate) async fn create_room_route(
|
||||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&create_event_content)?,
|
||||
state_key: Some(StateKey::new()),
|
||||
timestamp: custom_origin_server_ts,
|
||||
timestamp: create_timestamp,
|
||||
..Default::default()
|
||||
},
|
||||
sender_user,
|
||||
|
||||
Reference in new issue
Block a user