feat(services/autumn): authenticate the user on upload

feat(services/autumn): file size limits on upload
chore: add database migrations for new autumn things
This commit is contained in:
Paul Makles
2024-09-10 16:53:58 +01:00
parent 1a6a8a809b
commit 6209bc7152
12 changed files with 199 additions and 40 deletions

View File

@@ -100,6 +100,8 @@ blocked_mime_types = []
clamd_host = ""
[files.limit]
# Minimum file size (in bytes)
min_file_size = 1
# Minimum image resolution
min_resolution = [1, 1]
# Maximum MP of images
@@ -153,42 +155,66 @@ server_emoji = 100
server_roles = 200
server_channels = 200
# How many days since creation a user is considered new
new_user_days = 3
# How many hours since creation a user is considered new
new_user_hours = 72
# Maximum permissible body size in bytes for uploads
# (should be greater than any one file upload limit)
body_limit_size = 20_000_000
[features.limits.new_user]
# Limits imposed on new users
# Number of outgoing friend requests permitted at any time
outgoing_friend_requests = 5
# Maximum number of owned bots
bots = 2
message_length = 2000
message_attachments = 5
servers = 100
attachment_size = 20_000_000
avatar_size = 4_000_000
background_size = 6_000_000
icon_size = 2_500_000
banner_size = 6_000_000
emoji_size = 500_000
# Message content length
message_length = 2000
# Number of attachments that can be included
message_attachments = 5
# Maximum number of servers the user can create/join
servers = 50
[features.limits.new_user.file_upload_size_limit]
# Maximum file size limits (in bytes)
attachments = 20_000_000
avatars = 4_000_000
backgrounds = 6_000_000
icons = 2_500_000
banners = 6_000_000
emojis = 500_000
[features.limits.default]
# Limits imposed on users by default
# Number of outgoing friend requests permitted at any time
outgoing_friend_requests = 10
# Maximum number of owned bots
bots = 5
# Message content length
message_length = 2000
# Number of attachments that can be included
message_attachments = 5
# Maximum number of servers the user can create/join
servers = 100
attachment_size = 20_000_000
avatar_size = 4_000_000
background_size = 6_000_000
icon_size = 2_500_000
banner_size = 6_000_000
emoji_size = 500_000
[features.limits.default.file_upload_size_limit]
# Maximum file size limits (in bytes)
attachments = 20_000_000
avatars = 4_000_000
backgrounds = 6_000_000
icons = 2_500_000
banners = 6_000_000
emojis = 500_000
[sentry]
# Configuration for Sentry error reporting

View File

@@ -136,6 +136,7 @@ pub struct Api {
#[derive(Deserialize, Debug, Clone)]
pub struct FilesLimit {
pub min_file_size: usize,
pub min_resolution: [usize; 2],
pub max_mega_pixels: usize,
pub max_pixel_side: usize,
@@ -172,7 +173,7 @@ pub struct GlobalLimits {
pub server_roles: usize,
pub server_channels: usize,
pub new_user_days: usize,
pub new_user_hours: usize,
pub body_limit_size: usize,
}
@@ -186,12 +187,7 @@ pub struct FeaturesLimits {
pub message_attachments: usize,
pub servers: usize,
pub attachment_size: usize,
pub avatar_size: usize,
pub background_size: usize,
pub icon_size: usize,
pub banner_size: usize,
pub emoji_size: usize,
pub file_upload_size_limit: HashMap<String, usize>,
}
#[derive(Deserialize, Debug, Clone)]

View File

@@ -56,6 +56,10 @@ pub async fn create_database(db: &MongoDb) {
.await
.expect("Failed to create attachments collection.");
db.create_collection("attachment_hashes", None)
.await
.expect("Failed to create attachment_hashes collection.");
db.create_collection("user_settings", None)
.await
.expect("Failed to create user_settings collection.");
@@ -209,6 +213,40 @@ pub async fn create_database(db: &MongoDb) {
.await
.expect("Failed to create server_members index.");
db.run_command(
doc! {
"createIndexes": "attachments",
"indexes": [
{
"key": {
"hash": 1_i32
},
"name": "hash"
}
]
},
None,
)
.await
.expect("Failed to create attachments index.");
db.run_command(
doc! {
"createIndexes": "attachment_hashes",
"indexes": [
{
"key": {
"processed_hash": 1_i32
},
"name": "processed_hash"
}
]
},
None,
)
.await
.expect("Failed to create attachment_hashes index.");
db.collection("migrations")
.insert_one(
doc! {

View File

@@ -20,7 +20,7 @@ struct MigrationInfo {
revision: i32,
}
pub const LATEST_REVISION: i32 = 28;
pub const LATEST_REVISION: i32 = 29;
pub async fn migrate_database(db: &MongoDb) {
let migrations = db.col::<Document>("migrations");
@@ -1094,6 +1094,51 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
.expect("Failed to create message index.");
}
if revision <= 28 {
info!("Running migration [revision 28 / 10-09-2024]: Add support for new Autumn.");
db.db()
.create_collection("attachment_hashes", None)
.await
.ok();
db.db()
.run_command(
doc! {
"createIndexes": "attachments",
"indexes": [
{
"key": {
"hash": 1_i32
},
"name": "hash"
}
]
},
None,
)
.await
.expect("Failed to create attachments index.");
db.db()
.run_command(
doc! {
"createIndexes": "attachment_hashes",
"indexes": [
{
"key": {
"processed_hash": 1_i32
},
"name": "processed_hash"
}
]
},
None,
)
.await
.expect("Failed to create attachment_hashes index.");
}
// Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`.
// Reminder to update LATEST_REVISION when adding new migrations.

View File

@@ -74,6 +74,9 @@ impl IntoResponse for Error {
ErrorType::FailedValidation { .. } => StatusCode::BAD_REQUEST,
ErrorType::ProxyError => StatusCode::BAD_REQUEST,
ErrorType::FileTooSmall => StatusCode::UNPROCESSABLE_ENTITY,
ErrorType::FileTooLarge { .. } => StatusCode::UNPROCESSABLE_ENTITY,
ErrorType::FileTypeNotAllowed => StatusCode::BAD_REQUEST,
};
(status, Json(&self)).into_response()

View File

@@ -156,6 +156,11 @@ pub enum ErrorType {
// ? Micro-service errors
ProxyError,
FileTooSmall,
FileTooLarge {
max: usize,
},
FileTypeNotAllowed,
// ? Legacy errors
VosoUnavailable,

View File

@@ -80,6 +80,9 @@ impl<'r> Responder<'r, 'static> for Error {
ErrorType::FailedValidation { .. } => Status::BadRequest,
ErrorType::ProxyError => Status::BadRequest,
ErrorType::FileTooSmall => Status::UnprocessableEntity,
ErrorType::FileTooLarge { .. } => Status::UnprocessableEntity,
ErrorType::FileTypeNotAllowed => Status::BadRequest,
};
// Serialize the error data structure into JSON.