aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaiddog <[email protected]>2017-08-27 04:17:59 -0500
committeralex <[email protected]>2017-08-27 11:17:59 +0200
commite1a8fe3e9f619fbb94dd54993c8f5d25fd5dc375 (patch)
tree4c6c45cc592505f971c13aee8dfbdd41107a84ce /src
parentAdd ability to play DCA and Opus files. (#148) (diff)
downloadserenity-e1a8fe3e9f619fbb94dd54993c8f5d25fd5dc375.tar.xz
serenity-e1a8fe3e9f619fbb94dd54993c8f5d25fd5dc375.zip
Prevent malformed opus data from crashing the bot process (#149)
Diffstat (limited to 'src')
-rw-r--r--src/client/context.rs36
-rw-r--r--src/client/dispatch.rs124
-rw-r--r--src/gateway/shard.rs72
-rw-r--r--src/model/channel/reaction.rs53
-rw-r--r--src/model/user.rs61
-rw-r--r--src/voice/streamer.rs5
6 files changed, 186 insertions, 165 deletions
diff --git a/src/client/context.rs b/src/client/context.rs
index d0600b6..1bd5ed7 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -78,23 +78,25 @@ impl Context {
pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F) -> Result<CurrentUser> {
let mut map = Map::new();
- feature_cache! {{
- let cache = CACHE.read().unwrap();
-
- map.insert("username".to_owned(), Value::String(cache.user.name.clone()));
-
- if let Some(email) = cache.user.email.as_ref() {
- map.insert("email".to_owned(), Value::String(email.clone()));
- }
- } else {
- let user = http::get_current_user()?;
-
- map.insert("username".to_owned(), Value::String(user.name.clone()));
-
- if let Some(email) = user.email.as_ref() {
- map.insert("email".to_owned(), Value::String(email.clone()));
- }
- }}
+ feature_cache! {
+ {
+ let cache = CACHE.read().unwrap();
+
+ map.insert("username".to_owned(), Value::String(cache.user.name.clone()));
+
+ if let Some(email) = cache.user.email.as_ref() {
+ map.insert("email".to_owned(), Value::String(email.clone()));
+ }
+ } else {
+ let user = http::get_current_user()?;
+
+ map.insert("username".to_owned(), Value::String(user.name.clone()));
+
+ if let Some(email) = user.email.as_ref() {
+ map.insert("email".to_owned(), Value::String(email.clone()));
+ }
+ }
+ }
let edited = f(EditProfile(map)).0;
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs
index 461fe8c..68f31ef 100644
--- a/src/client/dispatch.rs
+++ b/src/client/dispatch.rs
@@ -386,26 +386,28 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
let h = event_handler.clone();
- feature_cache! {{
- // This is safe to unwrap, as the update would have created
- // the member if it did not exist. So, there is be _no_ way
- // that this could fail under any circumstance.
- let after = CACHE.read()
- .unwrap()
- .member(event.guild_id, event.user.id)
- .unwrap()
- .clone();
-
- tokio_handle.spawn_fn(move || {
- h.on_guild_member_update(context, _before, after);
- Ok(())
- });
- } else {
- tokio_handle.spawn_fn(move || {
- h.on_guild_member_update(context, event);
- Ok(())
- });
- }}
+ feature_cache! {
+ {
+ // This is safe to unwrap, as the update would have created
+ // the member if it did not exist. So, there is be _no_ way
+ // that this could fail under any circumstance.
+ let after = CACHE.read()
+ .unwrap()
+ .member(event.guild_id, event.user.id)
+ .unwrap()
+ .clone();
+
+ tokio_handle.spawn_fn(move || {
+ h.on_guild_member_update(context, _before, after);
+ Ok(())
+ });
+ } else {
+ tokio_handle.spawn_fn(move || {
+ h.on_guild_member_update(context, event);
+ Ok(())
+ });
+ }
+ }
},
Event::GuildMembersChunk(event) => {
update!(update_with_guild_members_chunk, event);
@@ -484,23 +486,25 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
let h = event_handler.clone();
- feature_cache! {{
- let before = CACHE.read()
- .unwrap()
- .guilds
- .get(&event.guild.id)
- .cloned();
-
- tokio_handle.spawn_fn(move || {
- h.on_guild_update(context, before, event.guild);
- Ok(())
- });
- } else {
- tokio_handle.spawn_fn(move || {
- h.on_guild_update(context, event.guild);
- Ok(())
- });
- }}
+ feature_cache! {
+ {
+ let before = CACHE.read()
+ .unwrap()
+ .guilds
+ .get(&event.guild.id)
+ .cloned();
+
+ tokio_handle.spawn_fn(move || {
+ h.on_guild_update(context, before, event.guild);
+ Ok(())
+ });
+ } else {
+ tokio_handle.spawn_fn(move || {
+ h.on_guild_update(context, event.guild);
+ Ok(())
+ });
+ }
+ }
},
// Already handled by the framework check macro
Event::MessageCreate(_) => {},
@@ -593,28 +597,30 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
Event::Ready(event) => {
update!(update_with_ready, event);
- feature_cache!{{
- last_guild_create_time = now!();
-
- let _ = wait_for_guilds()
- .map(|_| {
- let context = context(conn, data);
-
- let h = event_handler.clone();
- tokio_handle.spawn_fn(move || {
- h.on_ready(context, event.ready);
- Ok(())
- });
- });
- } else {
- let context = context(conn, data);
-
- let h = event_handler.clone();
- tokio_handle.spawn_fn(move || {
- h.on_ready(context, event.ready);
- Ok(())
- });
- }}
+ feature_cache!{
+ {
+ last_guild_create_time = now!();
+
+ let _ = wait_for_guilds()
+ .map(|_| {
+ let context = context(conn, data);
+
+ let h = event_handler.clone();
+ tokio_handle.spawn_fn(move || {
+ h.on_ready(context, event.ready);
+ Ok(())
+ });
+ });
+ } else {
+ let context = context(conn, data);
+
+ let h = event_handler.clone();
+ tokio_handle.spawn_fn(move || {
+ h.on_ready(context, event.ready);
+ Ok(())
+ });
+ }
+ }
},
Event::Resumed(event) => {
let context = context(conn, data);
diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs
index 6f6a949..028efeb 100644
--- a/src/gateway/shard.rs
+++ b/src/gateway/shard.rs
@@ -138,41 +138,43 @@ impl Shard {
let session_id = None;
let mut shard =
- feature_voice! {{
- let (tx, rx) = mpsc::channel();
-
- let user = http::get_current_user()?;
-
- Shard {
- client,
- current_presence,
- heartbeat_instants,
- heartbeat_interval,
- last_heartbeat_acknowledged,
- seq,
- stage,
- token,
- session_id,
- shard_info,
- ws_url,
- manager: VoiceManager::new(tx, user.id),
- manager_rx: rx,
- }
- } else {
- Shard {
- client,
- current_presence,
- heartbeat_instants,
- heartbeat_interval,
- last_heartbeat_acknowledged,
- seq,
- stage,
- token,
- session_id,
- shard_info,
- ws_url,
- }
- }};
+ feature_voice! {
+ {
+ let (tx, rx) = mpsc::channel();
+
+ let user = http::get_current_user()?;
+
+ Shard {
+ client,
+ current_presence,
+ heartbeat_instants,
+ heartbeat_interval,
+ last_heartbeat_acknowledged,
+ seq,
+ stage,
+ token,
+ session_id,
+ shard_info,
+ ws_url,
+ manager: VoiceManager::new(tx, user.id),
+ manager_rx: rx,
+ }
+ } else {
+ Shard {
+ client,
+ current_presence,
+ heartbeat_instants,
+ heartbeat_interval,
+ last_heartbeat_acknowledged,
+ seq,
+ stage,
+ token,
+ session_id,
+ shard_info,
+ ws_url,
+ }
+ }
+ };
shard.identify()?;
diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs
index be5dfb8..121bf43 100644
--- a/src/model/channel/reaction.rs
+++ b/src/model/channel/reaction.rs
@@ -46,31 +46,34 @@ impl Reaction {
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
/// [permissions]: permissions
pub fn delete(&self) -> Result<()> {
- let user_id = feature_cache! {{
- let user = if self.user_id == CACHE.read().unwrap().user.id {
- None
- } else {
- Some(self.user_id.0)
- };
-
- // If the reaction is one _not_ made by the current user, then ensure
- // that the current user has permission* to delete the reaction.
- //
- // Normally, users can only delete their own reactions.
- //
- // * The `Manage Messages` permission.
- if user.is_some() {
- let req = permissions::MANAGE_MESSAGES;
-
- if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- user
- } else {
- Some(self.user_id.0)
- }};
+ let user_id =
+ feature_cache! {
+ {
+ let user = if self.user_id == CACHE.read().unwrap().user.id {
+ None
+ } else {
+ Some(self.user_id.0)
+ };
+
+ // If the reaction is one _not_ made by the current user, then ensure
+ // that the current user has permission* to delete the reaction.
+ //
+ // Normally, users can only delete their own reactions.
+ //
+ // * The `Manage Messages` permission.
+ if user.is_some() {
+ let req = permissions::MANAGE_MESSAGES;
+
+ if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
+ return Err(Error::Model(ModelError::InvalidPermissions(req)));
+ }
+ }
+
+ user
+ } else {
+ Some(self.user_id.0)
+ }
+ };
http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
}
diff --git a/src/model/user.rs b/src/model/user.rs
index 66b7285..359d497 100644
--- a/src/model/user.rs
+++ b/src/model/user.rs
@@ -492,35 +492,38 @@ impl User {
return Err(Error::Model(ModelError::MessagingBot));
}
- let private_channel_id = feature_cache! {{
- let finding = {
- let cache = CACHE.read().unwrap();
-
- let finding = cache.private_channels
- .values()
- .map(|ch| ch.read().unwrap())
- .find(|ch| ch.recipient.read().unwrap().id == self.id)
- .map(|ch| ch.id);
-
- finding
- };
-
- if let Some(finding) = finding {
- finding
- } else {
- let map = json!({
- "recipient_id": self.id.0,
- });
-
- http::create_private_channel(&map)?.id
- }
- } else {
- let map = json!({
- "recipient_id": self.id.0,
- });
-
- http::create_private_channel(&map)?.id
- }};
+ let private_channel_id =
+ feature_cache! {
+ {
+ let finding = {
+ let cache = CACHE.read().unwrap();
+
+ let finding = cache.private_channels
+ .values()
+ .map(|ch| ch.read().unwrap())
+ .find(|ch| ch.recipient.read().unwrap().id == self.id)
+ .map(|ch| ch.id);
+
+ finding
+ };
+
+ if let Some(finding) = finding {
+ finding
+ } else {
+ let map = json!({
+ "recipient_id": self.id.0,
+ });
+
+ http::create_private_channel(&map)?.id
+ }
+ } else {
+ let map = json!({
+ "recipient_id": self.id.0,
+ });
+
+ http::create_private_channel(&map)?.id
+ }
+ };
private_channel_id.send_message(f)
}
diff --git a/src/voice/streamer.rs b/src/voice/streamer.rs
index 5f05879..cf62d27 100644
--- a/src/voice/streamer.rs
+++ b/src/voice/streamer.rs
@@ -48,6 +48,11 @@ impl<R: Read + Send> AudioSource for InputSource<R> {
fn read_opus_frame(&mut self) -> Option<Vec<u8>> {
match self.reader.read_i16::<LittleEndian>() {
Ok(size) => {
+ if size <= 0 {
+ warn!("Invalid opus frame size: {}", size);
+ return None;
+ }
+
let mut frame = Vec::with_capacity(size as usize);
{