Compare commits

...
4 Commits
21 changed files with 137 additions and 88 deletions
Generated
+8 -8
View File
@@ -3452,7 +3452,7 @@ dependencies = [
[[package]]
name = "revolt-bonfire"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"async-channel 2.3.1",
"async-std",
@@ -3482,7 +3482,7 @@ dependencies = [
[[package]]
name = "revolt-config"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"async-std",
"cached",
@@ -3498,7 +3498,7 @@ dependencies = [
[[package]]
name = "revolt-database"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"async-lock",
"async-recursion",
@@ -3544,7 +3544,7 @@ dependencies = [
[[package]]
name = "revolt-delta"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"async-channel 1.6.1",
"async-std",
@@ -3590,7 +3590,7 @@ dependencies = [
[[package]]
name = "revolt-models"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"indexmap",
"iso8601-timestamp 0.2.11",
@@ -3607,7 +3607,7 @@ dependencies = [
[[package]]
name = "revolt-permissions"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"async-std",
"async-trait",
@@ -3622,7 +3622,7 @@ dependencies = [
[[package]]
name = "revolt-presence"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"async-std",
"log",
@@ -3633,7 +3633,7 @@ dependencies = [
[[package]]
name = "revolt-result"
version = "0.7.9"
version = "0.7.10"
dependencies = [
"revolt_okapi",
"revolt_rocket_okapi",
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-bonfire"
version = "0.7.9"
version = "0.7.10"
license = "AGPL-3.0-or-later"
edition = "2021"
@@ -41,7 +41,7 @@ revolt-result = { path = "../core/result" }
revolt-models = { path = "../core/models" }
revolt-config = { path = "../core/config" }
revolt-database = { path = "../core/database" }
revolt-permissions = { version = "0.7.9", path = "../core/permissions" }
revolt-permissions = { version = "0.7.10", path = "../core/permissions" }
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
# redis
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-config"
version = "0.7.9"
version = "0.7.10"
edition = "2021"
license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"]
+26 -7
View File
@@ -46,21 +46,40 @@ webhooks_enabled = false
[features.limits]
[features.limits.default]
outgoing_friend_requests = 10
[features.limits.global]
group_size = 100
bots = 5
message_length = 2000
message_embeds = 5
message_replies = 5
message_attachments = 5
message_reactions = 20
servers = 100
server_emoji = 100
server_roles = 200
server_channels = 200
new_user_days = 3
[features.limits.new_user]
outgoing_friend_requests = 5
bots = 2
message_length = 2000
message_attachments = 5
servers = 100
attachment_size = 20000000
avatar_size = 4000000
background_size = 6000000
icon_size = 2500000
banner_size = 6000000
emoji_size = 500000
[features.limits.default]
outgoing_friend_requests = 10
bots = 5
message_length = 2000
message_attachments = 5
servers = 100
attachment_size = 20000000
avatar_size = 4000000
background_size = 6000000
+17 -8
View File
@@ -105,21 +105,27 @@ pub struct Api {
}
#[derive(Deserialize, Debug, Clone)]
pub struct FeaturesLimits {
pub outgoing_friend_requests: usize,
pub struct GlobalLimits {
pub group_size: usize,
pub bots: usize,
pub message_length: usize,
pub message_replies: usize,
pub message_attachments: usize,
pub message_embeds: usize,
pub message_replies: usize,
pub message_reactions: usize,
pub servers: usize,
pub server_emoji: usize,
pub server_roles: usize,
pub server_channels: usize,
pub new_user_days: usize,
}
#[derive(Deserialize, Debug, Clone)]
pub struct FeaturesLimits {
pub outgoing_friend_requests: usize,
pub bots: usize,
pub message_length: usize,
pub message_attachments: usize,
pub servers: usize,
pub attachment_size: usize,
pub avatar_size: usize,
pub background_size: usize,
@@ -130,6 +136,9 @@ pub struct FeaturesLimits {
#[derive(Deserialize, Debug, Clone)]
pub struct FeaturesLimitsCollection {
pub global: GlobalLimits,
pub new_user: FeaturesLimits,
pub default: FeaturesLimits,
#[serde(flatten)]
+6 -6
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-database"
version = "0.7.9"
version = "0.7.10"
edition = "2021"
license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"]
@@ -23,13 +23,13 @@ default = ["mongodb", "async-std-runtime", "tasks"]
[dependencies]
# Core
revolt-config = { version = "0.7.9", path = "../config" }
revolt-result = { version = "0.7.9", path = "../result" }
revolt-models = { version = "0.7.9", path = "../models", features = [
revolt-config = { version = "0.7.10", path = "../config" }
revolt-result = { version = "0.7.10", path = "../result" }
revolt-models = { version = "0.7.10", path = "../models", features = [
"validator",
] }
revolt-presence = { version = "0.7.9", path = "../presence" }
revolt-permissions = { version = "0.7.9", path = "../permissions", features = [
revolt-presence = { version = "0.7.10", path = "../presence" }
revolt-permissions = { version = "0.7.10", path = "../permissions", features = [
"serde",
"bson",
] }
@@ -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));
}
@@ -201,9 +201,9 @@ impl Channel {
update_server: bool,
) -> Result<Channel> {
let config = config().await;
if server.channels.len() > config.features.limits.default.server_channels {
if server.channels.len() > config.features.limits.global.server_channels {
return Err(create_error!(TooManyChannels {
max: config.features.limits.default.server_channels,
max: config.features.limits.global.server_channels,
}));
};
@@ -263,9 +263,9 @@ impl Channel {
data.users.insert(owner_id.to_string());
let config = config().await;
if data.users.len() > config.features.limits.default.group_size {
if data.users.len() > config.features.limits.global.group_size {
return Err(create_error!(GroupTooLarge {
max: config.features.limits.default.group_size,
max: config.features.limits.global.group_size,
}));
}
@@ -346,9 +346,9 @@ impl Channel {
}
let config = config().await;
if recipients.len() >= config.features.limits.default.group_size {
if recipients.len() >= config.features.limits.global.group_size {
return Err(create_error!(GroupTooLarge {
max: config.features.limits.default.group_size
max: config.features.limits.global.group_size
}));
}
@@ -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
@@ -288,9 +290,9 @@ impl Message {
// Verify replies are valid.
let mut replies = HashSet::new();
if let Some(entries) = data.replies {
if entries.len() > config.features.limits.default.message_replies {
if entries.len() > config.features.limits.global.message_replies {
return Err(create_error!(TooManyReplies {
max: config.features.limits.default.message_replies,
max: config.features.limits.global.message_replies,
}));
}
@@ -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,
}));
}
@@ -616,7 +618,7 @@ impl Message {
pub async fn add_reaction(&self, db: &Database, user: &User, emoji: &str) -> Result<()> {
// Check how many reactions are already on the message
let config = config().await;
if self.reactions.len() >= config.features.limits.default.message_reactions
if self.reactions.len() >= config.features.limits.global.message_reactions
&& !self.reactions.contains_key(emoji)
{
return Err(create_error!(InvalidOperation));
@@ -781,7 +783,7 @@ impl Interactions {
if let Some(reactions) = &self.reactions {
permissions.throw_if_lacking_channel_permission(ChannelPermission::React)?;
if reactions.len() > config.features.limits.default.message_reactions {
if reactions.len() > config.features.limits.global.message_reactions {
return Err(create_error!(InvalidOperation));
}
+41 -23
View File
@@ -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
}))
}
}
@@ -470,24 +485,6 @@ impl User {
/// Add another user as a friend
pub async fn add_friend(&mut self, db: &Database, target: &mut User) -> Result<()> {
let count = self
.relations
.as_ref()
.map(|relations| {
relations
.iter()
.filter(|r| matches!(r.status, RelationshipStatus::Outgoing))
.count()
})
.unwrap_or_default();
let config = config().await;
if count >= config.features.limits.default.outgoing_friend_requests {
return Err(create_error!(TooManyPendingFriendRequests {
max: config.features.limits.default.outgoing_friend_requests
}));
}
match self.relationship_with(&target.id) {
RelationshipStatus::User => Err(create_error!(NoEffect)),
RelationshipStatus::Friend => Err(create_error!(AlreadyFriends)),
@@ -495,6 +492,7 @@ impl User {
RelationshipStatus::Blocked => Err(create_error!(Blocked)),
RelationshipStatus::BlockedOther => Err(create_error!(BlockedByOther)),
RelationshipStatus::Incoming => {
// Accept incoming friend request
self.apply_relationship(
db,
target,
@@ -504,6 +502,26 @@ impl User {
.await
}
RelationshipStatus::None => {
// Get this user's current count of outgoing friend requests
let count = self
.relations
.as_ref()
.map(|relations| {
relations
.iter()
.filter(|r| matches!(r.status, RelationshipStatus::Outgoing))
.count()
})
.unwrap_or_default();
// If we're over the limit, don't allow creating more requests
if count >= self.limits().await.outgoing_friend_requests {
return Err(create_error!(TooManyPendingFriendRequests {
max: self.limits().await.outgoing_friend_requests
}));
}
// Send the friend request
self.apply_relationship(
db,
target,
@@ -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;
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-models"
version = "0.7.9"
version = "0.7.10"
edition = "2021"
license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"]
@@ -19,8 +19,8 @@ default = ["serde", "partials", "rocket"]
[dependencies]
# Core
revolt-config = { version = "0.7.9", path = "../config" }
revolt-permissions = { version = "0.7.9", path = "../permissions" }
revolt-config = { version = "0.7.10", path = "../config" }
revolt-permissions = { version = "0.7.10", path = "../permissions" }
# Utility
regex = "1"
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-permissions"
version = "0.7.9"
version = "0.7.10"
edition = "2021"
license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"]
@@ -21,7 +21,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
[dependencies]
# Core
revolt-result = { version = "0.7.9", path = "../result" }
revolt-result = { version = "0.7.10", path = "../result" }
# Utility
auto_ops = "0.3.0"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-presence"
version = "0.7.9"
version = "0.7.10"
edition = "2021"
license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-result"
version = "0.7.9"
version = "0.7.10"
edition = "2021"
license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "revolt-delta"
version = "0.7.9"
version = "0.7.10"
license = "AGPL-3.0-or-later"
authors = ["Paul Makles <paulmakles@gmail.com>"]
edition = "2018"
@@ -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
@@ -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,
@@ -45,9 +45,9 @@ pub async fn create_emoji(
// Check that we haven't hit the emoji limit
let emojis = db.fetch_emoji_by_parent_id(&server.id).await?;
if emojis.len() >= config.features.limits.default.server_emoji {
if emojis.len() >= config.features.limits.global.server_emoji {
return Err(create_error!(TooManyEmoji {
max: config.features.limits.default.server_emoji,
max: config.features.limits.global.server_emoji,
}));
}
}
@@ -34,9 +34,9 @@ pub async fn create(
.throw_if_lacking_channel_permission(ChannelPermission::ManageRole)?;
let config = config().await;
if server.roles.len() >= config.features.limits.default.server_roles {
if server.roles.len() >= config.features.limits.global.server_roles {
return Err(create_error!(TooManyRoles {
max: config.features.limits.default.server_roles,
max: config.features.limits.global.server_roles,
}));
};
@@ -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,