From 456bf7b42abc768a10e437eab92d23903f6b7dce Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Wed, 25 Oct 2023 10:39:54 +0100 Subject: [PATCH] fix: check server ownership for text channel refactor: minor cleanup of code --- .../database/src/models/channels/model.rs | 145 ++++++++++++++++++ .../core/database/src/models/servers/model.rs | 20 +-- crates/core/database/src/util/idempotency.rs | 2 +- crates/core/database/src/util/permissions.rs | 1 + crates/core/permissions/src/impl.rs | 4 +- crates/core/presence/src/lib.rs | 1 - .../routes/channels/group_remove_member.rs | 1 + 7 files changed, 155 insertions(+), 19 deletions(-) diff --git a/crates/core/database/src/models/channels/model.rs b/crates/core/database/src/models/channels/model.rs index 9e1f6b7b..0f1ec626 100644 --- a/crates/core/database/src/models/channels/model.rs +++ b/crates/core/database/src/models/channels/model.rs @@ -624,3 +624,148 @@ impl IntoDocumentPath for FieldsChannel { }) } } + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use revolt_permissions::{calculate_channel_permissions, ChannelPermission, OverrideField}; + + use crate::{ + util::permissions::DatabasePermissionQuery, Channel, Member, MemberCompositeKey, Role, + Server, User, + }; + + #[async_std::test] + async fn permissions_text_channel() { + database_test!(|db| async move { + let owner = User::create(&db, "Owner".to_string(), None, None) + .await + .unwrap(); + + let moderator = User::create(&db, "Moderator".to_string(), None, None) + .await + .unwrap(); + + let user = User::create(&db, "User".to_string(), None, None) + .await + .unwrap(); + + let server_id = ulid::Ulid::new().to_string(); + + let channel = Channel::TextChannel { + id: ulid::Ulid::new().to_string(), + server: server_id.clone(), + name: "Channel".to_string(), + description: None, + icon: None, + last_message_id: None, + default_permissions: Some(OverrideField { + d: 1048576, // TODO: bitfield + ..Default::default() + }), + role_permissions: HashMap::from([( + "01F9HFTSBWTNA2F4TMSV7VM3FG".to_string(), + OverrideField { + a: 1048576, // TODO: bitfield + ..Default::default() + }, + )]), + nsfw: false, + }; + + let server = Server { + id: server_id, + owner: owner.id.clone(), + name: "My Server".to_string(), + description: None, + channels: vec![channel.id()], + categories: None, + system_messages: None, + roles: HashMap::from([ + ( + "01F9HFTSBWTNA2F4TMSV7VM3FG".to_string(), + Role { + name: "Moderator".to_string(), + permissions: OverrideField { + a: 545270208, // TODO: explicit + ..Default::default() + }, + colour: None, + hoist: true, + rank: 3, + }, + ), + ( + "01FBF9DNHSRPVTWFMNB3JNB8FK".to_string(), + Role { + name: "Owner".to_string(), + permissions: Default::default(), + colour: None, + hoist: true, + rank: 0, + }, + ), + ]), + default_permissions: 4000322560, // TODO: use bitfield + icon: None, + banner: None, + flags: None, + nsfw: false, + analytics: false, + discoverable: false, + }; + + // TODO: proper creation + db.insert_channel(&channel).await.unwrap(); + server.create(&db).await.unwrap(); + + db.insert_member(&Member { + id: MemberCompositeKey { + user: owner.id.clone(), + server: server.id.clone(), + }, + roles: vec!["01FBF9DNHSRPVTWFMNB3JNB8FK".to_string()], + ..Default::default() + }) + .await + .unwrap(); + + db.insert_member(&Member { + id: MemberCompositeKey { + user: moderator.id.clone(), + server: server.id.clone(), + }, + roles: vec!["01F9HFTSBWTNA2F4TMSV7VM3FG".to_string()], + ..Default::default() + }) + .await + .unwrap(); + + db.insert_member(&Member { + id: MemberCompositeKey { + user: user.id.clone(), + server: server.id.clone(), + }, + ..Default::default() + }) + .await + .unwrap(); + + let mut query = DatabasePermissionQuery::new(&db, &owner).channel(&channel); + assert!(calculate_channel_permissions(&mut query) + .await + .has_channel_permission(ChannelPermission::SendMessage)); + + let mut query = DatabasePermissionQuery::new(&db, &moderator).channel(&channel); + assert!(calculate_channel_permissions(&mut query) + .await + .has_channel_permission(ChannelPermission::SendMessage)); + + let mut query = DatabasePermissionQuery::new(&db, &user).channel(&channel); + assert!(!calculate_channel_permissions(&mut query) + .await + .has_channel_permission(ChannelPermission::SendMessage)); + }); + } +} diff --git a/crates/core/database/src/models/servers/model.rs b/crates/core/database/src/models/servers/model.rs index 3af796eb..8c12eaa8 100644 --- a/crates/core/database/src/models/servers/model.rs +++ b/crates/core/database/src/models/servers/model.rs @@ -458,8 +458,7 @@ mod tests { use revolt_permissions::{calculate_server_permissions, ChannelPermission, OverrideField}; use crate::{ - util::permissions::DatabasePermissionQuery, Channel, Member, MemberCompositeKey, Role, - Server, User, + util::permissions::DatabasePermissionQuery, Member, MemberCompositeKey, Role, Server, User, }; #[async_std::test] @@ -479,24 +478,14 @@ mod tests { let server_id = ulid::Ulid::new().to_string(); - let channel = Channel::TextChannel { - id: ulid::Ulid::new().to_string(), - server: server_id.clone(), - name: "Channel".to_string(), - description: None, - icon: None, - last_message_id: None, - default_permissions: None, - role_permissions: HashMap::new(), - nsfw: false, - }; - + // TODO: seeder functions + // e.g. seed!("channel", "file.json") let server = Server { id: server_id, owner: owner.id.clone(), name: "My Server".to_string(), description: None, - channels: vec![channel.id()], + channels: vec![], categories: None, system_messages: None, roles: HashMap::from([ @@ -534,7 +523,6 @@ mod tests { }; // TODO: proper creation - db.insert_channel(&channel).await.unwrap(); server.create(&db).await.unwrap(); db.insert_member(&Member { diff --git a/crates/core/database/src/util/idempotency.rs b/crates/core/database/src/util/idempotency.rs index e12fe2f5..791a61dd 100644 --- a/crates/core/database/src/util/idempotency.rs +++ b/crates/core/database/src/util/idempotency.rs @@ -1,6 +1,6 @@ use std::num::NonZeroUsize; -use revolt_result::{create_error, Result}; +use revolt_result::{create_error, Result, Error}; use async_std::sync::Mutex; use once_cell::sync::Lazy; diff --git a/crates/core/database/src/util/permissions.rs b/crates/core/database/src/util/permissions.rs index 68fbfda9..c9d67fa8 100644 --- a/crates/core/database/src/util/permissions.rs +++ b/crates/core/database/src/util/permissions.rs @@ -344,6 +344,7 @@ impl PermissionQuery for DatabasePermissionQuery<'_> { | Cow::Owned(Channel::TextChannel { server, .. }) | Cow::Borrowed(Channel::VoiceChannel { server, .. }) | Cow::Owned(Channel::VoiceChannel { server, .. }) => { + // FIXME: may double fetch if let Ok(server) = self.database.fetch_server(server).await { self.server.replace(Cow::Owned(server)); } diff --git a/crates/core/permissions/src/impl.rs b/crates/core/permissions/src/impl.rs index e3af670b..039a1076 100644 --- a/crates/core/permissions/src/impl.rs +++ b/crates/core/permissions/src/impl.rs @@ -104,7 +104,9 @@ pub async fn calculate_channel_permissions(query: &mut P) -> ChannelType::ServerChannel => { query.set_server_from_channel().await; - if query.are_we_a_member().await { + if query.are_we_server_owner().await { + return ChannelPermission::GrantAllSafe.into(); + } else if query.are_we_a_member().await { let mut permissions = calculate_server_permissions(query).await; permissions.apply(query.get_default_channel_permissions().await); diff --git a/crates/core/presence/src/lib.rs b/crates/core/presence/src/lib.rs index c510e494..f0c9e6ac 100644 --- a/crates/core/presence/src/lib.rs +++ b/crates/core/presence/src/lib.rs @@ -221,7 +221,6 @@ mod tests { // Create a few more sessions let (first_session, second_session_id) = create_session(&user_id, 0).await; assert!(!first_session); - dbg!(second_session_id); assert_eq!(second_session_id as u8 & 1, 0); let (first_session, other_session_id) = create_session(&other_id, 0).await; diff --git a/crates/delta/src/routes/channels/group_remove_member.rs b/crates/delta/src/routes/channels/group_remove_member.rs index ce1cf0d1..b7be015c 100644 --- a/crates/delta/src/routes/channels/group_remove_member.rs +++ b/crates/delta/src/routes/channels/group_remove_member.rs @@ -148,6 +148,7 @@ mod test { .await; dbg!(response.into_string().await); + // TODO: finish impl // assert_eq!(response.status(), Status::NotFound); }