tuwunel_admin/federation/
commands.rs1use futures::StreamExt;
2use ruma::{OwnedRoomId, OwnedServerName, OwnedUserId};
3use tuwunel_core::{Err, Result};
4
5use crate::{admin_command, get_room_info};
6
7#[admin_command]
8pub(super) async fn disable_room(&self, room_id: OwnedRoomId) -> Result {
9 self.services.metadata.disable_room(&room_id);
10 self.write_str("Room disabled.").await
11}
12
13#[admin_command]
14pub(super) async fn enable_room(&self, room_id: OwnedRoomId) -> Result {
15 self.services.metadata.enable_room(&room_id);
16 self.write_str("Room enabled.").await
17}
18
19#[admin_command]
20pub(super) async fn incoming_federation(&self) -> Result {
21 Err!("This command is temporarily disabled")
22}
23
24#[admin_command]
25pub(super) async fn fetch_support_well_known(&self, server_name: OwnedServerName) -> Result {
26 let response = self
27 .services
28 .client
29 .default
30 .get(format!("https://{server_name}/.well-known/matrix/support"))
31 .send()
32 .await?;
33
34 let text = response.text().await?;
35
36 if text.is_empty() {
37 return Err!("Response text/body is empty.");
38 }
39
40 if text.len() > 1500 {
41 return Err!(
42 "Response text/body is over 1500 characters, assuming no support well-known.",
43 );
44 }
45
46 let json: serde_json::Value = match serde_json::from_str(&text) {
47 | Ok(json) => json,
48 | Err(_) => {
49 return Err!("Response text/body is not valid JSON.",);
50 },
51 };
52
53 let pretty_json: String = match serde_json::to_string_pretty(&json) {
54 | Ok(json) => json,
55 | Err(_) => {
56 return Err!("Response text/body is not valid JSON.",);
57 },
58 };
59
60 self.write_str(&format!("Got JSON response:\n\n```json\n{pretty_json}\n```"))
61 .await
62}
63
64#[admin_command]
65pub(super) async fn remote_user_in_rooms(&self, user_id: OwnedUserId) -> Result {
66 if user_id.server_name() == self.services.server.name {
67 return Err!(
68 "User belongs to our server, please use `list-joined-rooms` user admin command \
69 instead.",
70 );
71 }
72
73 if !self.services.users.exists(&user_id).await {
74 return Err!("Remote user does not exist in our database.",);
75 }
76
77 let mut rooms: Vec<(OwnedRoomId, u64, String)> = self
78 .services
79 .state_cache
80 .rooms_joined(&user_id)
81 .then(|room_id| get_room_info(self.services, room_id))
82 .collect()
83 .await;
84
85 if rooms.is_empty() {
86 return Err!("User is not in any rooms.");
87 }
88
89 rooms.sort_by_key(|r| r.1);
90 rooms.reverse();
91
92 let num = rooms.len();
93 let body = rooms
94 .iter()
95 .map(|(id, members, name)| format!("{id} | Members: {members} | Name: {name}"))
96 .collect::<Vec<_>>()
97 .join("\n");
98
99 self.write_str(&format!("Rooms {user_id} shares with us ({num}):\n```\n{body}\n```"))
100 .await
101}