diff --git a/crates/core/config/Revolt.toml b/crates/core/config/Revolt.toml index 9f5c0c262..3fa1fe804 100644 --- a/crates/core/config/Revolt.toml +++ b/crates/core/config/Revolt.toml @@ -48,6 +48,7 @@ webhooks_enabled = false [features.limits.global] group_size = 100 +message_embeds = 5 message_replies = 5 message_reactions = 20 server_emoji = 100 @@ -61,7 +62,6 @@ outgoing_friend_requests = 5 bots = 2 message_length = 2000 -message_embeds = 5 message_attachments = 5 servers = 100 @@ -77,7 +77,6 @@ outgoing_friend_requests = 10 bots = 5 message_length = 2000 -message_embeds = 5 message_attachments = 5 servers = 100 diff --git a/crates/core/config/src/lib.rs b/crates/core/config/src/lib.rs index 02d238dd6..701fc14d1 100644 --- a/crates/core/config/src/lib.rs +++ b/crates/core/config/src/lib.rs @@ -107,6 +107,7 @@ pub struct Api { #[derive(Deserialize, Debug, Clone)] pub struct GlobalLimits { pub group_size: usize, + pub message_embeds: usize, pub message_replies: usize, pub message_reactions: usize, pub server_emoji: usize, @@ -123,7 +124,6 @@ pub struct FeaturesLimits { pub bots: usize, pub message_length: usize, pub message_attachments: usize, - pub message_embeds: usize, pub servers: usize, pub attachment_size: usize, diff --git a/crates/core/database/src/models/bots/model.rs b/crates/core/database/src/models/bots/model.rs index 6b2134328..cb36d0085 100644 --- a/crates/core/database/src/models/bots/model.rs +++ b/crates/core/database/src/models/bots/model.rs @@ -80,8 +80,7 @@ impl Bot { return Err(create_error!(IsBot)); } - let config = config().await; - if db.get_number_of_bots_by_user(&owner.id).await? >= config.features.limits.default.bots { + if db.get_number_of_bots_by_user(&owner.id).await? >= owner.limits().await.bots { return Err(create_error!(ReachedMaximumBots)); } diff --git a/crates/core/database/src/models/messages/model.rs b/crates/core/database/src/models/messages/model.rs index afafff91a..b46e73c79 100644 --- a/crates/core/database/src/models/messages/model.rs +++ b/crates/core/database/src/models/messages/model.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use indexmap::{IndexMap, IndexSet}; use iso8601_timestamp::Timestamp; -use revolt_config::config; +use revolt_config::{config, FeaturesLimits}; use revolt_models::v0::{ self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageSort, MessageWebhook, PushNotification, ReplyIntent, SendableEmbed, Text, RE_MENTION, @@ -207,11 +207,13 @@ impl Default for Message { #[allow(clippy::disallowed_methods)] impl Message { /// Create message from API data + #[allow(clippy::too_many_arguments)] pub async fn create_from_api( db: &Database, channel: Channel, data: DataMessageSend, author: MessageAuthor<'_>, + limits: FeaturesLimits, mut idempotency: IdempotencyKey, generate_embeds: bool, allow_mentions: bool, @@ -221,7 +223,7 @@ impl Message { Message::validate_sum( &data.content, data.embeds.as_deref().unwrap_or_default(), - config.features.limits.default.message_length, + limits.message_length, )?; idempotency @@ -320,20 +322,20 @@ impl Message { if data .attachments .as_ref() - .is_some_and(|v| v.len() > config.features.limits.default.message_attachments) + .is_some_and(|v| v.len() > limits.message_attachments) { return Err(create_error!(TooManyAttachments { - max: config.features.limits.default.message_attachments, + max: limits.message_attachments, })); } if data .embeds .as_ref() - .is_some_and(|v| v.len() > config.features.limits.default.message_embeds) + .is_some_and(|v| v.len() > config.features.limits.global.message_embeds) { return Err(create_error!(TooManyEmbeds { - max: config.features.limits.default.message_embeds, + max: config.features.limits.global.message_embeds, })); } diff --git a/crates/core/database/src/models/users/model.rs b/crates/core/database/src/models/users/model.rs index 1a3b9820b..c434291d8 100644 --- a/crates/core/database/src/models/users/model.rs +++ b/crates/core/database/src/models/users/model.rs @@ -1,10 +1,10 @@ -use std::{collections::HashSet, time::Duration}; +use std::{collections::HashSet, str::FromStr, time::Duration}; use crate::{events::client::EventV1, Database, File, RatelimitEvent}; use once_cell::sync::Lazy; use rand::seq::SliceRandom; -use revolt_config::config; +use revolt_config::{config, FeaturesLimits}; use revolt_models::v0; use revolt_presence::filter_online; use revolt_result::{create_error, Result}; @@ -197,6 +197,22 @@ impl User { Ok(user) } + /// Get limits for this user + pub async fn limits(&self) -> FeaturesLimits { + let config = config().await; + if ulid::Ulid::from_str(&self.id) + .expect("`ulid`") + .datetime() + .elapsed() + .expect("time went backwards") + <= Duration::from_secs(86400u64 * config.features.limits.global.new_user_days as u64) + { + config.features.limits.new_user + } else { + config.features.limits.default + } + } + /// Get the relationship with another user pub fn relationship_with(&self, user_b: &str) -> RelationshipStatus { if self.id == user_b { @@ -235,12 +251,11 @@ impl User { /// Check if this user can acquire another server pub async fn can_acquire_server(&self, db: &Database) -> Result<()> { - let config = config().await; - if db.fetch_server_count(&self.id).await? <= config.features.limits.default.servers { + if db.fetch_server_count(&self.id).await? <= self.limits().await.servers { Ok(()) } else { Err(create_error!(TooManyServers { - max: config.features.limits.default.servers + max: self.limits().await.servers })) } } @@ -500,10 +515,9 @@ impl User { .unwrap_or_default(); // If we're over the limit, don't allow creating more requests - let config = config().await; - if count >= config.features.limits.default.outgoing_friend_requests { + if count >= self.limits().await.outgoing_friend_requests { return Err(create_error!(TooManyPendingFriendRequests { - max: config.features.limits.default.outgoing_friend_requests + max: self.limits().await.outgoing_friend_requests })); } diff --git a/crates/core/database/src/tasks/process_embeds.rs b/crates/core/database/src/tasks/process_embeds.rs index 459b8b3ad..d9d61d75a 100644 --- a/crates/core/database/src/tasks/process_embeds.rs +++ b/crates/core/database/src/tasks/process_embeds.rs @@ -56,7 +56,7 @@ pub async fn worker(db: Database) { let embeds = generate( task.content, &config.hosts.january, - config.features.limits.default.message_embeds, + config.features.limits.global.message_embeds, semaphore, ) .await; diff --git a/crates/delta/src/routes/channels/message_edit.rs b/crates/delta/src/routes/channels/message_edit.rs index 4c1a78b95..41958e34e 100644 --- a/crates/delta/src/routes/channels/message_edit.rs +++ b/crates/delta/src/routes/channels/message_edit.rs @@ -30,11 +30,10 @@ pub async fn edit( }) })?; - let config = config().await; Message::validate_sum( &edit.content, edit.embeds.as_deref().unwrap_or_default(), - config.features.limits.default.message_length, + user.limits().await.message_length, )?; // Ensure we have permissions to send a message diff --git a/crates/delta/src/routes/channels/message_send.rs b/crates/delta/src/routes/channels/message_send.rs index ab83be956..28b906519 100644 --- a/crates/delta/src/routes/channels/message_send.rs +++ b/crates/delta/src/routes/channels/message_send.rs @@ -81,6 +81,7 @@ pub async fn message_send( channel, data, v0::MessageAuthor::User(&author), + user.limits().await, idempotency, permissions.has_channel_permission(ChannelPermission::SendEmbeds), allow_mentions, diff --git a/crates/delta/src/routes/webhooks/webhook_execute.rs b/crates/delta/src/routes/webhooks/webhook_execute.rs index f370b1861..6a6eebc44 100644 --- a/crates/delta/src/routes/webhooks/webhook_execute.rs +++ b/crates/delta/src/routes/webhooks/webhook_execute.rs @@ -1,3 +1,4 @@ +use revolt_config::config; use revolt_database::{ util::{idempotency::IdempotencyKey, reference::Reference}, Database, Message, @@ -58,6 +59,7 @@ pub async fn webhook_execute( channel, data, v0::MessageAuthor::Webhook(&webhook.into()), + config().await.features.limits.default, idempotency, true, true,