diff --git a/book/changelog.md b/book/changelog.md index d552c3fa..c02ba451 100644 --- a/book/changelog.md +++ b/book/changelog.md @@ -331,3 +331,6 @@ This will be the first release of Grapevine since it was forked from Conduit ([!158](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/158)) 27. Transfer local canonical aliases to the new room when upgrading a room. ([!186](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/186)) +28. Attempt to remove alias from m.room.canonical_alias event when deleting a + local alias. + ([!186](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/186)) diff --git a/src/api/client_server/alias.rs b/src/api/client_server/alias.rs index 5ec165f5..06febd74 100644 --- a/src/api/client_server/alias.rs +++ b/src/api/client_server/alias.rs @@ -8,10 +8,16 @@ use ruma::{ }, federation, }, + events::{ + room::canonical_alias::RoomCanonicalAliasEventContent, StateEventType, + TimelineEventType, + }, OwnedRoomAliasId, }; +use serde_json::value::to_raw_value; +use tracing::info; -use crate::{services, Ar, Error, Ra, Result}; +use crate::{service::pdu::PduBuilder, services, Ar, Error, Ra, Result}; /// # `PUT /_matrix/client/r0/directory/room/{roomAlias}` /// @@ -75,12 +81,13 @@ pub(crate) async fn delete_alias_route( )); } - if services().rooms.alias.resolve_local_alias(&body.room_alias)?.is_none() { - return Err(Error::BadRequest( - ErrorKind::NotFound, - "Alias is not assigned.", - )); - } + let room_id = services() + .rooms + .alias + .resolve_local_alias(&body.room_alias)? + .ok_or_else(|| { + Error::BadRequest(ErrorKind::NotFound, "Alias is not assigned.") + })?; if let Some(info) = &body.appservice_info { if !info.aliases.is_match(body.room_alias.as_str()) { @@ -98,7 +105,66 @@ pub(crate) async fn delete_alias_route( services().rooms.alias.remove_alias(&body.room_alias, sender_user)?; - // TODO: update alt_aliases? + // Attempt to remove the alias from the m.room.canonical_alias event, if it + // was present. + let canonical_alias: Option = services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomCanonicalAlias, "")? + .and_then(|event| { + serde_json::from_str(event.content.get()) + .inspect_err(|_| { + Error::bad_database("invalid m.room.canonical_alias event"); + }) + .ok() + }); + if let Some(mut canonical_alias) = canonical_alias { + let mut changed = false; + if canonical_alias.alias.as_ref() == Some(&body.room_alias) { + canonical_alias.alias = None; + changed = true; + } + canonical_alias.alt_aliases.retain(|a| { + let equal = a == &body.room_alias; + changed |= equal; + !equal + }); + + if changed { + let room_token = services() + .globals + .roomid_mutex_state + .lock_key(room_id.clone()) + .await; + + if let Err(error) = services() + .rooms + .timeline + .build_and_append_pdu( + PduBuilder { + event_type: TimelineEventType::RoomCanonicalAlias, + content: to_raw_value(&canonical_alias) + .expect("event is valid"), + unsigned: None, + state_key: Some(String::new()), + redacts: None, + }, + sender_user, + &room_token, + ) + .await + { + // > Servers which choose to update the canonical alias event + // > are recommended to, in addition to their other relevant + // > permission checks, delete the alias and return a successful + // > response even if the user does not have permission to + // > update the m.room.canonical_alias event. + // + // + info!(%error, "Failed to remove canonical alias"); + } + } + } Ok(Ra(delete_alias::v3::Response::new())) }