diff --git a/Cargo.lock b/Cargo.lock index 0fdc2ac9..a186e4ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4671,7 +4671,7 @@ dependencies = [ "log", "parking_lot", "pbjson-types", - "prost 0.12.6", + "prost", "rand 0.9.2", "reqwest 0.11.27", "scopeguard", @@ -4693,7 +4693,7 @@ dependencies = [ "parking_lot", "pbjson", "pbjson-types", - "prost 0.12.6", + "prost", "prost-types", "serde", "thiserror 1.0.69", @@ -5484,90 +5484,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" -dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "pin-project-lite 0.2.16", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "opentelemetry-appender-tracing" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" -dependencies = [ - "opentelemetry", - "tracing", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "opentelemetry-http" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" -dependencies = [ - "async-trait", - "bytes 1.10.1", - "http 1.3.1", - "opentelemetry", - "reqwest 0.12.23", -] - -[[package]] -name = "opentelemetry-otlp" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" -dependencies = [ - "http 1.3.1", - "opentelemetry", - "opentelemetry-http", - "opentelemetry-proto", - "opentelemetry_sdk", - "prost 0.14.3", - "reqwest 0.12.23", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" -dependencies = [ - "opentelemetry", - "opentelemetry_sdk", - "prost 0.14.3", - "tonic", - "tonic-prost", -] - -[[package]] -name = "opentelemetry_sdk" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" -dependencies = [ - "futures-channel", - "futures-executor", - "futures-util", - "opentelemetry", - "percent-encoding", - "rand 0.9.2", - "thiserror 2.0.18", -] - [[package]] name = "ordered-multimap" version = "0.4.3" @@ -5696,7 +5612,7 @@ checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" dependencies = [ "heck 0.4.1", "itertools 0.11.0", - "prost 0.12.6", + "prost", "prost-types", ] @@ -5710,7 +5626,7 @@ dependencies = [ "chrono", "pbjson", "pbjson-build", - "prost 0.12.6", + "prost", "prost-build", "serde", ] @@ -6293,17 +6209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes 1.10.1", - "prost-derive 0.12.6", -] - -[[package]] -name = "prost" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" -dependencies = [ - "bytes 1.10.1", - "prost-derive 0.14.3", + "prost-derive", ] [[package]] @@ -6320,7 +6226,7 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost 0.12.6", + "prost", "prost-types", "regex", "syn 2.0.106", @@ -6340,26 +6246,13 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "prost-derive" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote 1.0.40", - "syn 2.0.106", -] - [[package]] name = "prost-types" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost 0.12.6", + "prost", ] [[package]] @@ -6849,9 +6742,7 @@ dependencies = [ "base64 0.22.1", "bytes 1.10.1", "encoding_rs", - "futures-channel", "futures-core", - "futures-util", "h2 0.4.12", "http 1.3.1", "http-body 1.0.1", @@ -6921,10 +6812,6 @@ dependencies = [ "lazy_static", "moka", "nanoid", - "opentelemetry", - "opentelemetry-appender-tracing", - "opentelemetry-otlp", - "opentelemetry_sdk", "revolt-config", "revolt-database", "revolt-files", @@ -7161,6 +7048,7 @@ dependencies = [ "serde", "serde_json", "tokio 1.49.0", + "tower-http 0.5.2", "tracing", "utoipa", "utoipa-scalar", @@ -9217,38 +9105,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" -[[package]] -name = "tonic" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" -dependencies = [ - "async-trait", - "base64 0.22.1", - "bytes 1.10.1", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "percent-encoding", - "pin-project", - "sync_wrapper 1.0.2", - "tokio-stream", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-prost" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" -dependencies = [ - "bytes 1.10.1", - "prost 0.14.3", - "tonic", -] - [[package]] name = "totp-lite" version = "2.0.1" @@ -9291,7 +9147,6 @@ dependencies = [ "pin-project-lite 0.2.16", "tower-layer", "tower-service", - "tracing", ] [[package]] diff --git a/crates/core/database/src/models/server_members/model.rs b/crates/core/database/src/models/server_members/model.rs index 74ec04a8..0062a270 100644 --- a/crates/core/database/src/models/server_members/model.rs +++ b/crates/core/database/src/models/server_members/model.rs @@ -72,6 +72,7 @@ auto_derived!( CanReceive, CanPublish, JoinedAt, + VoiceChannel, } /// Member removal intention @@ -224,13 +225,14 @@ impl Member { pub fn remove_field(&mut self, field: &FieldsMember) { match field { - FieldsMember::JoinedAt => (), + FieldsMember::JoinedAt => {}, FieldsMember::Avatar => self.avatar = None, FieldsMember::Nickname => self.nickname = None, FieldsMember::Roles => self.roles.clear(), FieldsMember::Timeout => self.timeout = None, FieldsMember::CanReceive => self.can_receive = true, FieldsMember::CanPublish => self.can_publish = true, + FieldsMember::VoiceChannel => {}, } } diff --git a/crates/core/database/src/models/server_members/ops/mongodb.rs b/crates/core/database/src/models/server_members/ops/mongodb.rs index 198ad6a8..377e5877 100644 --- a/crates/core/database/src/models/server_members/ops/mongodb.rs +++ b/crates/core/database/src/models/server_members/ops/mongodb.rs @@ -330,14 +330,15 @@ impl AbstractServerMembers for MongoDb { impl IntoDocumentPath for FieldsMember { fn as_path(&self) -> Option<&'static str> { - Some(match self { - FieldsMember::JoinedAt => "joined_at", - FieldsMember::Avatar => "avatar", - FieldsMember::Nickname => "nickname", - FieldsMember::Roles => "roles", - FieldsMember::Timeout => "timeout", - FieldsMember::CanPublish => "can_publish", - FieldsMember::CanReceive => "can_receive", - }) + match self { + FieldsMember::JoinedAt => Some("joined_at"), + FieldsMember::Avatar => Some("avatar"), + FieldsMember::Nickname => Some("nickname"), + FieldsMember::Roles => Some("roles"), + FieldsMember::Timeout => Some("timeout"), + FieldsMember::CanPublish => Some("can_publish"), + FieldsMember::CanReceive => Some("can_receive"), + FieldsMember::VoiceChannel => None, + } } } diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index de63db90..aafb2313 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -691,6 +691,7 @@ impl From for FieldsMember { crate::FieldsMember::CanReceive => FieldsMember::CanReceive, crate::FieldsMember::CanPublish => FieldsMember::CanPublish, crate::FieldsMember::JoinedAt => FieldsMember::JoinedAt, + crate::FieldsMember::VoiceChannel => FieldsMember::VoiceChannel, } } } @@ -705,6 +706,7 @@ impl From for crate::FieldsMember { FieldsMember::CanReceive => crate::FieldsMember::CanReceive, FieldsMember::CanPublish => crate::FieldsMember::CanPublish, FieldsMember::JoinedAt => crate::FieldsMember::JoinedAt, + FieldsMember::VoiceChannel => crate::FieldsMember::VoiceChannel, } } } diff --git a/crates/core/models/src/v0/server_members.rs b/crates/core/models/src/v0/server_members.rs index d1ccb058..41ec99ae 100644 --- a/crates/core/models/src/v0/server_members.rs +++ b/crates/core/models/src/v0/server_members.rs @@ -95,6 +95,7 @@ auto_derived!( CanReceive, CanPublish, JoinedAt, + VoiceChannel, } /// Member removal intention diff --git a/crates/delta/src/main.rs b/crates/delta/src/main.rs index e7c060be..882609cc 100644 --- a/crates/delta/src/main.rs +++ b/crates/delta/src/main.rs @@ -70,6 +70,15 @@ pub async fn web() -> Rocket { .iter() .map(|s| FromStr::from_str(s).unwrap()) .collect(), + expose_headers: [ + "X-Ratelimit-Limit", + "X-Ratelimit-Bucket", + "X-Ratelimit-Remaining", + "X-Ratelimit-Reset-After", + ] + .iter() + .map(|s| s.to_string()) + .collect(), ..Default::default() } .to_cors() diff --git a/crates/delta/src/routes/servers/member_edit.rs b/crates/delta/src/routes/servers/member_edit.rs index 458c10ba..ecc1d919 100644 --- a/crates/delta/src/routes/servers/member_edit.rs +++ b/crates/delta/src/routes/servers/member_edit.rs @@ -98,13 +98,21 @@ pub async fn edit( permissions.throw_if_lacking_channel_permission(ChannelPermission::DeafenMembers)?; } - let new_voice_channel = if let Some(new_channel) = &data.voice_channel { + if data.voice_channel.is_some() && data.remove.contains(&FieldsMember::VoiceChannel) { + return Err(create_error!(InvalidOperation)) + } + + if data.voice_channel.is_some() || data.remove.contains(&FieldsMember::VoiceChannel) { if !voice_client.is_enabled() { return Err(create_error!(LiveKitUnavailable)); }; - permissions.throw_if_lacking_channel_permission(ChannelPermission::MoveMembers)?; + if member.id.user != user.id { + permissions.throw_if_lacking_channel_permission(ChannelPermission::MoveMembers)?; + } + } + let new_voice_channel = if let Some(new_channel) = &data.voice_channel { // ensure the channel we are moving them to is in the server and is a voice channel let channel = Reference::from_unchecked(new_channel) @@ -116,6 +124,9 @@ pub async fn edit( Err(create_error!(UnknownChannel))? } + let channel_permissions = calculate_channel_permissions(&mut query.clone().channel(&channel)).await; + channel_permissions.throw_if_lacking_channel_permission(ChannelPermission::Connect)?; + if get_user_voice_channel_in_server(&target_user.id, &server.id) .await? .is_none() @@ -189,10 +200,8 @@ pub async fn edit( partial.avatar = Some(File::use_user_avatar(db, &avatar, &user.id, &user.id).await?); } - let remove_contains_voice = remove.contains(FieldsMember::CanPublish) || remove.contains(FieldsMember::CanReceive); - member - .update(db, partial, remove.into_iter().map(Into::into).collect()) + .update(db, partial, remove.clone().into_iter().map(Into::into).collect()) .await?; if let Some(new_voice_channel) = new_voice_channel { @@ -234,7 +243,7 @@ pub async fn edit( .private(target_user.id.clone()) .await; }; - } else if can_publish.is_some() || can_receive.is_some() || remove_contains_voice { + } else if can_publish.is_some() || can_receive.is_some() || remove.contains(FieldsMember::CanPublish) || remove.contains(FieldsMember::CanReceive) { if let Some(channel) = get_user_voice_channel_in_server(&target_user.id, &server.id).await? { let node = get_channel_node(&channel).await?.unwrap(); @@ -253,5 +262,14 @@ pub async fn edit( }; }; + if remove.contains(&FieldsMember::VoiceChannel) { + if let Some(channel) = get_user_voice_channel_in_server(&target_user.id, &server.id).await? + { + let node = get_channel_node(&channel).await?.unwrap(); + + voice_client.remove_user(&node, &user.id, &channel).await?; + }; + } + Ok(Json(member.into())) } diff --git a/crates/services/autumn/src/api.rs b/crates/services/autumn/src/api.rs index 5c567146..d711e533 100644 --- a/crates/services/autumn/src/api.rs +++ b/crates/services/autumn/src/api.rs @@ -34,6 +34,12 @@ pub async fn router() -> Router { let cors = CorsLayer::new() .allow_methods([Method::POST]) .allow_headers(AllowHeaders::mirror_request()) + .expose_headers(vec![ + "X-RateLimit-Limit".try_into().unwrap(), + "X-RateLimit-Bucket".try_into().unwrap(), + "X-RateLimit-Remaining".try_into().unwrap(), + "X-RateLimit-Reset-After".try_into().unwrap(), + ]) .allow_origin(Any); Router::new() diff --git a/crates/services/gifbox/Cargo.toml b/crates/services/gifbox/Cargo.toml index fade557c..6588f8ef 100644 --- a/crates/services/gifbox/Cargo.toml +++ b/crates/services/gifbox/Cargo.toml @@ -36,6 +36,7 @@ revolt-ratelimits = { version = "0.9.4", path = "../../core/ratelimits", feature # Axum / web server axum = { version = "0.7.5" } axum-extra = { version = "0.9", features = ["typed-header"] } +tower-http = { version = "0.5.2", features = ["cors"] } # OpenAPI & documentation generation utoipa-scalar = { version = "0.1.0", features = ["axum"] } diff --git a/crates/services/gifbox/src/routes/mod.rs b/crates/services/gifbox/src/routes/mod.rs index efee317f..e47e19f0 100644 --- a/crates/services/gifbox/src/routes/mod.rs +++ b/crates/services/gifbox/src/routes/mod.rs @@ -1,5 +1,9 @@ use crate::AppState; -use axum::routing::{get, Router}; +use axum::{ + http::Method, + routing::{get, Router}, +}; +use tower_http::cors::{AllowHeaders, Any, CorsLayer}; pub mod categories; pub mod root; @@ -7,9 +11,21 @@ pub mod search; pub mod trending; pub fn router() -> Router { + let cors = CorsLayer::new() + .allow_methods([Method::GET]) + .allow_headers(AllowHeaders::mirror_request()) + .expose_headers(vec![ + "X-RateLimit-Limit".try_into().unwrap(), + "X-RateLimit-Bucket".try_into().unwrap(), + "X-RateLimit-Remaining".try_into().unwrap(), + "X-RateLimit-Reset-After".try_into().unwrap(), + ]) + .allow_origin(Any); + Router::new() .route("/", get(root::root)) .route("/categories", get(categories::categories)) .route("/search", get(search::search)) .route("/trending", get(trending::trending)) + .layer(cors) }