Skip to main content

tuwunel_admin/federation/
commands.rs

1use 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}