From 7066b7b4280d132e948a5ca1868f0da20e55d16e Mon Sep 17 00:00:00 2001
From: strawberry <strawberry@puppygock.gay>
Date: Wed, 20 Mar 2024 11:19:41 -0400
Subject: [PATCH] feat: automatically join rooms on registration

Signed-off-by: strawberry <strawberry@puppygock.gay>
---
 conduwuit-example.toml              |  5 +++++
 src/api/client_server/account.rs    | 31 +++++++++++++++++++++++++++--
 src/api/client_server/membership.rs |  2 +-
 src/config/mod.rs                   | 12 ++++++++++-
 src/service/globals/mod.rs          |  2 ++
 5 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/conduwuit-example.toml b/conduwuit-example.toml
index decaf406f..8ea1d4789 100644
--- a/conduwuit-example.toml
+++ b/conduwuit-example.toml
@@ -263,6 +263,11 @@ url_preview_check_root_domain = false
 # Defaults to true as this is the fastest option for federation.
 #query_trusted_key_servers_first = true
 
+# List/vector of room **IDs** that conduwuit will make newly registered users join.
+#
+# No default.
+#auto_join_rooms = []
+
 
 
 ### Generic database options
diff --git a/src/api/client_server/account.rs b/src/api/client_server/account.rs
index 260168027..295a08e3a 100644
--- a/src/api/client_server/account.rs
+++ b/src/api/client_server/account.rs
@@ -12,10 +12,13 @@
 	events::{room::message::RoomMessageEventContent, GlobalAccountDataEventType},
 	push, UserId,
 };
-use tracing::{info, warn};
+use tracing::{error, info, warn};
 
 use super::{DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH};
-use crate::{api::client_server, services, utils, Error, Result, Ruma};
+use crate::{
+	api::client_server::{self, join_room_by_id_helper},
+	services, utils, Error, Result, Ruma,
+};
 
 const RANDOM_USER_ID_LENGTH: usize = 10;
 
@@ -285,6 +288,30 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
 		}
 	}
 
+	if !services().globals.config.auto_join_rooms.is_empty() {
+		for room in &services().globals.config.auto_join_rooms {
+			if let Some(room_id_server_name) = room.server_name() {
+				match join_room_by_id_helper(
+					Some(&user_id),
+					room,
+					Some("Automatically joining this room".to_owned()),
+					&[room_id_server_name.to_owned()],
+					None,
+				)
+				.await
+				{
+					Ok(_) => {
+						info!("Automatically joined room {room} for user {user_id}");
+					},
+					Err(e) => {
+						// don't return this error so we don't fail registrations
+						error!("Failed to automatically join room {room} for user {user_id}: {e}");
+					},
+				};
+			}
+		}
+	}
+
 	Ok(register::v3::Response {
 		access_token: Some(token),
 		user_id,
diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs
index 96082f701..6a8f00d64 100644
--- a/src/api/client_server/membership.rs
+++ b/src/api/client_server/membership.rs
@@ -474,7 +474,7 @@ pub async fn joined_members_route(body: Ruma<joined_members::v3::Request>) -> Re
 	})
 }
 
-async fn join_room_by_id_helper(
+pub(crate) async fn join_room_by_id_helper(
 	sender_user: Option<&UserId>, room_id: &RoomId, reason: Option<String>, servers: &[OwnedServerName],
 	_third_party_signed: Option<&ThirdPartySigned>,
 ) -> Result<join_room_by_id::v3::Response> {
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 604cb8d8f..e56187661 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -10,7 +10,7 @@
 use figment::Figment;
 use itertools::Itertools;
 use regex::RegexSet;
-use ruma::{OwnedServerName, RoomVersionId};
+use ruma::{OwnedRoomId, OwnedServerName, RoomVersionId};
 use serde::{de::IgnoredAny, Deserialize};
 use tracing::{debug, error, warn};
 
@@ -110,6 +110,9 @@ pub struct Config {
 	#[serde(default = "default_turn_ttl")]
 	pub turn_ttl: u64,
 
+	#[serde(default = "Vec::new")]
+	pub auto_join_rooms: Vec<OwnedRoomId>,
+
 	#[serde(default = "default_rocksdb_log_level")]
 	pub rocksdb_log_level: String,
 	#[serde(default = "default_rocksdb_max_log_file_size")]
@@ -364,6 +367,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 				}
 				&lst.join(", ")
 			}),
+			("Auto Join Rooms", {
+				let mut lst = vec![];
+				for room in &self.auto_join_rooms {
+					lst.push(room);
+				}
+				&lst.into_iter().join(", ")
+			}),
 			#[cfg(feature = "compression-zstd")]
 			("zstd Response Body Compression", &self.zstd_compression.to_string()),
 			#[cfg(feature = "rocksdb")]
diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs
index 6858631ec..5a6c7ea60 100644
--- a/src/service/globals/mod.rs
+++ b/src/service/globals/mod.rs
@@ -327,6 +327,8 @@ pub fn turn_username(&self) -> &String { &self.config.turn_username }
 
 	pub fn turn_secret(&self) -> &String { &self.config.turn_secret }
 
+	pub fn auto_join_rooms(&self) -> &[OwnedRoomId] { &self.config.auto_join_rooms }
+
 	pub fn notification_push_path(&self) -> &String { &self.config.notification_push_path }
 
 	pub fn emergency_password(&self) -> &Option<String> { &self.config.emergency_password }
-- 
GitLab