feat: add webhook permissions

This commit is contained in:
Zomatree
2023-06-11 23:02:53 +01:00
committed by Paul Makles
parent 6e4798f1d4
commit 54878e8e8d
11 changed files with 81 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ use crate::{
};
use futures::StreamExt;
use rand::seq::SliceRandom;
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
use serde::{Deserialize, Serialize};
use unicode_segmentation::UnicodeSegmentation;
@@ -945,6 +946,23 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
)
.await
.expect("Failed to create username index.");
};
if revision <= 25 {
info!("Running migration [revision 25 / 11-06-2023]: Add permissions to webhooks.");
db.col::<Document>("webhooks")
.update_many(
doc! {},
doc! {
"$set": {
"permissions": *DEFAULT_WEBHOOK_PERMISSIONS as i64
}
},
None,
)
.await
.expect("Failed to update webhooks.");
}
if revision <= 25 {

View File

@@ -20,6 +20,9 @@ auto_derived_partial!(
/// The channel this webhook belongs to
pub channel_id: String,
/// The permissions of the webhook
pub permissions: u64,
/// The private token for the webhook
pub token: Option<String>,
},

View File

@@ -52,6 +52,7 @@ impl From<crate::Webhook> for Webhook {
avatar: value.avatar.map(|file| file.into()),
channel_id: value.channel_id,
token: value.token,
permissions: value.permissions
}
}
}
@@ -64,6 +65,7 @@ impl From<crate::PartialWebhook> for PartialWebhook {
avatar: value.avatar.map(|file| file.into()),
channel_id: value.channel_id,
token: value.token,
permissions: value.permissions
}
}
}

View File

@@ -16,6 +16,9 @@ auto_derived_partial!(
/// The channel this webhook belongs to
pub channel_id: String,
/// The permissions for the webhook
pub permissions: u64,
/// The private token for the webhook
pub token: Option<String>,
},
@@ -43,6 +46,9 @@ auto_derived!(
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
pub avatar: Option<String>,
/// Webhook permissions
pub permissions: Option<u64>,
/// Fields to remove from webhook
#[cfg_attr(feature = "serde", serde(default))]
pub remove: Vec<FieldsWebhook>,
@@ -61,6 +67,9 @@ auto_derived!(
/// The channel this webhook belongs to
pub channel_id: String,
/// The permissions for the webhook
pub permissions: u64
}
/// Optional fields on webhook object
@@ -85,6 +94,7 @@ impl From<Webhook> for ResponseWebhook {
name: value.name,
avatar: value.avatar.map(|file| file.id),
channel_id: value.channel_id,
permissions: value.permissions
}
}
}

View File

@@ -135,3 +135,5 @@ pub static DEFAULT_PERMISSION_SERVER: Lazy<u64> = Lazy::new(|| {
+ ChannelPermission::ChangeAvatar,
)
});
pub static DEFAULT_WEBHOOK_PERMISSIONS: Lazy<u64> = Lazy::new(|| ChannelPermission::SendMessage + ChannelPermission::SendEmbeds + ChannelPermission::Masquerade + ChannelPermission::React);

View File

@@ -2,6 +2,7 @@ use revolt_database::{Database, Webhook};
use revolt_quark::{
models::{Channel, User},
perms, Db, Error, Permission, Ref, Result,
DEFAULT_WEBHOOK_PERMISSIONS,
};
use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize};
@@ -60,6 +61,7 @@ pub async fn req(
name: data.name,
avatar,
channel_id: channel.id().to_string(),
permissions: *DEFAULT_WEBHOOK_PERMISSIONS,
token: Some(nanoid::nanoid!(64)),
};

View File

@@ -35,11 +35,13 @@ pub async fn webhook_edit(
let DataEditWebhook {
name,
avatar,
permissions,
remove,
} = data;
let mut partial = PartialWebhook {
name,
permissions,
..Default::default()
};

View File

@@ -33,11 +33,13 @@ pub async fn webhook_edit_token(
let DataEditWebhook {
name,
avatar,
remove,
permissions,
remove
} = data;
let mut partial = PartialWebhook {
name,
permissions,
..Default::default()
};

View File

@@ -29,8 +29,7 @@ pub async fn webhook_execute(
let webhook = webhook_id.as_webhook(db).await.map_err(Error::from_core)?;
webhook.assert_token(&token).map_err(Error::from_core)?;
// TODO: webhooks can currently always send masquerades, files, embeds, reactions (interactions)
// TODO: they can also mention anyone
data.validate_webhook_permissions(webhook.permissions)?;
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
let message = channel

View File

@@ -10,7 +10,7 @@ use crate::{
models::{
message::{
AppendMessage, BulkMessageResponse, Interactions, PartialMessage, SendableEmbed,
SystemMessage,
SystemMessage, DataMessageSend,
},
Channel, Emoji, Message, User,
},
@@ -451,3 +451,39 @@ impl Interactions {
!self.restrict_reactions && self.reactions.is_none()
}
}
fn throw_permission(permissions: u64, permission: Permission) -> Result<()> {
if (permission as u64) & permissions == (permission as u64) {
Ok(())
} else {
Err(Error::MissingPermission { permission })
}
}
impl DataMessageSend {
pub fn validate_webhook_permissions(
&self,
permissions: u64,
) -> Result<()> {
throw_permission(permissions, Permission::SendMessage)?;
if self.attachments.as_ref().map_or(false, |v| !v.is_empty()) {
throw_permission(permissions, Permission::UploadFiles)?;
};
if self.embeds.as_ref().map_or(false, |v| !v.is_empty()) {
throw_permission(permissions, Permission::SendEmbeds)?;
};
if self.masquerade.is_some() {
throw_permission(permissions, Permission::Masquerade)?;
};
if self.interactions.is_some() {
throw_permission(permissions, Permission::React)?;
};
Ok(())
}
}

View File

@@ -110,6 +110,7 @@ pub static DEFAULT_PERMISSION: Lazy<u64> = Lazy::new(|| DEFAULT_PERMISSION_VIEW_
pub static DEFAULT_PERMISSION_SAVED_MESSAGES: u64 = Permission::GrantAllSafe as u64;
pub static DEFAULT_PERMISSION_DIRECT_MESSAGE: Lazy<u64> = Lazy::new(|| DEFAULT_PERMISSION.add(Permission::ManageChannel + Permission::React));
pub static DEFAULT_PERMISSION_SERVER: Lazy<u64> = Lazy::new(|| DEFAULT_PERMISSION.add(Permission::React + Permission::ChangeNickname + Permission::ChangeAvatar));
pub static DEFAULT_WEBHOOK_PERMISSIONS: Lazy<u64> = Lazy::new(|| Permission::SendMessage + Permission::SendEmbeds + Permission::Masquerade + Permission::React);
bitfield! {
#[derive(Default)]