Fix privilege escalation when guests invite people

Conrad Irwin created

Change summary

crates/collab/src/db/queries/rooms.rs | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

Detailed changes

crates/collab/src/db/queries/rooms.rs 🔗

@@ -156,6 +156,24 @@ impl Database {
         initial_project_id: Option<ProjectId>,
     ) -> Result<RoomGuard<(proto::Room, proto::IncomingCall)>> {
         self.room_transaction(room_id, |tx| async move {
+            let room = self.get_room(room_id, &tx).await?;
+
+            let caller = room_participant::Entity::find()
+                .filter(
+                    room_participant::Column::UserId
+                        .eq(calling_user_id)
+                        .and(room_participant::Column::RoomId.eq(room_id)),
+                )
+                .one(&*tx)
+                .await?
+                .ok_or_else(|| anyhow!("user is not in the room"))?;
+
+            let called_user_role = match caller.role.unwrap_or(ChannelRole::Member) {
+                ChannelRole::Admin | ChannelRole::Member => ChannelRole::Member,
+                ChannelRole::Guest => ChannelRole::Guest,
+                ChannelRole::Banned => return Err(anyhow!("banned users cannot invite").into()),
+            };
+
             room_participant::ActiveModel {
                 room_id: ActiveValue::set(room_id),
                 user_id: ActiveValue::set(called_user_id),
@@ -167,7 +185,7 @@ impl Database {
                     calling_connection.owner_id as i32,
                 ))),
                 initial_project_id: ActiveValue::set(initial_project_id),
-                role: ActiveValue::set(Some(ChannelRole::Member)),
+                role: ActiveValue::set(Some(called_user_role)),
 
                 id: ActiveValue::NotSet,
                 answering_connection_id: ActiveValue::NotSet,
@@ -178,7 +196,6 @@ impl Database {
             .insert(&*tx)
             .await?;
 
-            let room = self.get_room(room_id, &tx).await?;
             let incoming_call = Self::build_incoming_call(&room, called_user_id)
                 .ok_or_else(|| anyhow!("failed to build incoming call"))?;
             Ok((room, incoming_call))