diff --git a/.gitignore b/.gitignore index 943bcfea..5bd774a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ Rocket.toml -Revolt.toml +Revolt.*.toml target .data diff --git a/Revolt.toml b/Revolt.toml new file mode 100644 index 00000000..71b71d46 --- /dev/null +++ b/Revolt.toml @@ -0,0 +1,199 @@ +# ⚠️ This configuration is intended for development environment. +# If you'd like to override anything, create a Revolt.override.toml + +[database] +# MongoDB connection URL +# Defaults to the container name specified in self-hosted +mongodb = "mongodb://localhost:14017" +# Redis connection URL +# Defaults to the container name specified in self-hosted +redis = "redis://localhost:14079/" + +[hosts] +# Web locations of various services +# Defaults assume all services are reverse-proxied +# See https://github.com/revoltchat/self-hosted/blob/master/Caddyfile +# +# Remember to change these to https/wss where appropriate in production! +app = "http://local.revolt.chat:14701" +api = "http://local.revolt.chat:14702" +events = "ws://local.revolt.chat:14703" +autumn = "http://local.revolt.chat:14704" +january = "http://local.revolt.chat:14705" +voso_legacy = "" +voso_legacy_ws = "" + +[api] + +[api.registration] +# Whether an invite should be required for registration +# See https://github.com/revoltchat/self-hosted#making-your-instance-invite-only +invite_only = false + +[api.smtp] +# Email server configuration for verification +# Defaults to no email verification (host field is empty) +host = "localhost" +username = "smtp" +password = "smtp" +from_address = "development@revolt.chat" +reply_to = "support@revolt.chat" +port = 14025 +use_tls = false + +[api.vapid] +# Generate your own keys: +# 1. Run `openssl ecparam -name prime256v1 -genkey -noout -out vapid_private.pem` +# 2. Find `private_key` using `base64 vapid_private.pem` +# 3. Find `public_key` using `openssl ec -in vapid_private.pem -outform DER|tail -c 65|base64|tr '/+' '_-'|tr -d '\n'` +private_key = "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUJSUWpyTWxLRnBiVWhsUHpUbERvcEliYk1yeVNrNXpKYzVYVzIxSjJDS3hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWnkrQkg2TGJQZ2hEa3pEempXOG0rUXVPM3pCajRXT1phdkR6ZU00c0pqbmFwd1psTFE0WAp1ZDh2TzVodU94QWhMQlU3WWRldVovWHlBdFpWZmNyQi9BPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo" +public_key = "BGcvgR-i2z4IQ5Mw841vJvkLjt8wY-FjmWrw83jOLCY52qcGZS0OF7nfLzuYbjsQISwVO2HXrmf18gLWVX3Kwfw=" + +[api.fcm] +# Google Firebase Cloud Messaging Service Account Key +# Obtained from the cloud messaging console +key_type = "" +project_id = "" +private_key_id = "" +private_key = "" +client_email = "" +client_id = "" +auth_uri = "" +token_uri = "" +auth_provider_x509_cert_url = "" +client_x509_cert_url = "" + +[api.apn] +# Apple Push Notifications keys for sending notifications +sandbox = false +pkcs8 = "" +key_id = "" +team_id = "" + +[api.security] +# Authifier Shield API key +authifier_shield_key = "" +# Legacy voice server management token +voso_legacy_token = "" +# Whether services are behind the Cloudflare network +trust_cloudflare = false + +[api.security.captcha] +# hCaptcha configuration +hcaptcha_key = "" +hcaptcha_sitekey = "" + +[api.workers] +# Maximum concurrent connections (to proxy server) +max_concurrent_connections = 50 + +[files] +# Encryption key for stored files +# Generate your own key using `openssl rand -base64 32` +encryption_key = "qcuMA+ssxhMyKaNAKBGFfryfFtUH8NDlamQyDwGW6fU=" +# Quality used for lossy WebP previews (set to 100 for lossless) +webp_quality = 80.0 +# Mime types that cannot be uploaded or served +# +# Example for Windows executables and Android installation files: +# ["application/vnd.microsoft.portable-executable", "application/vnd.android.package-archive"] +blocked_mime_types = [] +# ClamAV service +# hostname:port +clamd_host = "" + +[files.limit] +# Minimum image resolution +min_resolution = [1, 1] +# Maximum MP of images +max_mega_pixels = 40 +# Maximum pixel side of an image +max_pixel_side = 10_000 + +[files.preview] +# Maximum image resolution +attachments = [1280, 1280] +avatars = [128, 128] +backgrounds = [1280, 720] +icons = [128, 128] +banners = [480, 480] +emojis = [128, 128] + +[files.s3] +# Configuration for S3 +# Defaults included for MinIO + self-hosted setup +# +# Backblaze B2: +# - endpoint is listed on the "Buckets" page +# - region is `eu-central-003` string from endpoint URL +# - access_key_id is keyID generated on the "Application Keys" page +# - secret_access_key is token generated on the "Application Keys" page +# - default_bucket matches the name of the bucket you've created + +# S3 protocol endpoint +endpoint = "http://localhost:14009" +# S3 region name +region = "minio" +# S3 protocol key ID +access_key_id = "minioautumn" +# S3 protocol access key +secret_access_key = "minioautumn" +# Bucket to upload to by default +default_bucket = "revolt-uploads" + +[features] +# Feature gate options +webhooks_enabled = false + +[features.limits] + +[features.limits.global] +group_size = 100 +message_embeds = 5 +message_replies = 5 +message_reactions = 20 +server_emoji = 100 +server_roles = 200 +server_channels = 200 + +# How many days since creation a user is considered new +new_user_days = 3 + +# 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] +outgoing_friend_requests = 5 + +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 + +[features.limits.default] +outgoing_friend_requests = 10 + +bots = 5 +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 + +[sentry] +# Configuration for Sentry error reporting +api = "" +events = "" diff --git a/compose.yml b/compose.yml index f8edcf7b..8e4f3ce7 100644 --- a/compose.yml +++ b/compose.yml @@ -41,3 +41,15 @@ services: /usr/bin/mc mb minio/revolt-uploads; exit 0; " + + # Mock SMTP server + maildev: + image: soulteary/maildev + ports: + - "14025:8080" + - "14080:8080" + environment: + MAILDEV_SMTP_PORT: 25 + MAILDEV_WEB_PORT: 8080 + MAILDEV_INCOMING_USER: smtp + MAILDEV_INCOMING_PASS: smtp diff --git a/crates/bonfire/src/main.rs b/crates/bonfire/src/main.rs index 856eb243..62766cf7 100644 --- a/crates/bonfire/src/main.rs +++ b/crates/bonfire/src/main.rs @@ -22,8 +22,8 @@ async fn main() { clear_region(None).await; // Setup a TCP listener to accept WebSocket connections on. - // By default, we bind to port 9000 on all interfaces. - let bind = env::var("HOST").unwrap_or_else(|_| "0.0.0.0:9000".into()); + // By default, we bind to port 14703 on all interfaces. + let bind = env::var("HOST").unwrap_or_else(|_| "0.0.0.0:14703".into()); info!("Listening on host {bind}"); let try_socket = TcpListener::bind(bind).await; let listener = try_socket.expect("Failed to bind"); diff --git a/crates/core/config/Revolt.toml b/crates/core/config/Revolt.toml index 0f78139d..23181762 100644 --- a/crates/core/config/Revolt.toml +++ b/crates/core/config/Revolt.toml @@ -90,6 +90,14 @@ max_concurrent_connections = 50 encryption_key = "qcuMA+ssxhMyKaNAKBGFfryfFtUH8NDlamQyDwGW6fU=" # Quality used for lossy WebP previews (set to 100 for lossless) webp_quality = 80.0 +# Mime types that cannot be uploaded or served +# +# Example for Windows executables and Android installation files: +# ["application/vnd.microsoft.portable-executable", "application/vnd.android.package-archive"] +blocked_mime_types = [] +# ClamAV service +# hostname:port +clamd_host = "" [files.limit] # Minimum image resolution diff --git a/crates/core/config/src/lib.rs b/crates/core/config/src/lib.rs index 9868a24f..6e1b9732 100644 --- a/crates/core/config/src/lib.rs +++ b/crates/core/config/src/lib.rs @@ -146,6 +146,9 @@ pub struct FilesS3 { pub struct Files { pub encryption_key: String, pub webp_quality: f32, + pub blocked_mime_types: Vec, + pub clamd_host: String, + pub limit: FilesLimit, pub preview: HashMap, pub s3: FilesS3, diff --git a/crates/core/database/src/models/file_hashes/model.rs b/crates/core/database/src/models/file_hashes/model.rs index a1208901..703d17ea 100644 --- a/crates/core/database/src/models/file_hashes/model.rs +++ b/crates/core/database/src/models/file_hashes/model.rs @@ -40,7 +40,11 @@ auto_derived!( /// File contains textual data and should be displayed as such Text, /// File is an image with specific dimensions - Image { width: isize, height: isize }, + Image { + width: isize, + height: isize, + // animated: bool // TODO: https://docs.rs/image/latest/image/trait.AnimationDecoder.html + }, /// File is a video with specific dimensions Video { width: isize, height: isize }, /// File is audio diff --git a/crates/delta/src/main.rs b/crates/delta/src/main.rs index fc5b33d5..958254cd 100644 --- a/crates/delta/src/main.rs +++ b/crates/delta/src/main.rs @@ -97,6 +97,7 @@ pub async fn web() -> Rocket { .configure(rocket::Config { limits: rocket::data::Limits::default().limit("string", 5.megabytes()), address: Ipv4Addr::new(0, 0, 0, 0).into(), + port: 14702, ..Default::default() }) } diff --git a/crates/services/autumn/src/main.rs b/crates/services/autumn/src/main.rs index add11d2e..cf741f79 100644 --- a/crates/services/autumn/src/main.rs +++ b/crates/services/autumn/src/main.rs @@ -69,7 +69,7 @@ async fn main() -> Result<(), std::io::Error> { .with_state(db); // Configure TCP listener and bind - let address = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 3000)); + let address = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 14704)); let listener = TcpListener::bind(&address).await?; axum::serve(listener, app.into_make_service()).await } diff --git a/crates/services/january/src/main.rs b/crates/services/january/src/main.rs index 1d72fabc..08020f21 100644 --- a/crates/services/january/src/main.rs +++ b/crates/services/january/src/main.rs @@ -65,7 +65,7 @@ async fn main() -> Result<(), std::io::Error> { .nest("/", api::router().await); // Configure TCP listener and bind - let address = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 3000)); + let address = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 14705)); let listener = TcpListener::bind(&address).await?; axum::serve(listener, app.into_make_service()).await }