From 222382ca48cb9786aaf5d0b5fc16958e482e7c5f Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sat, 6 Jan 2018 15:02:05 -0800 Subject: Add some role position hierarchy checks --- src/model/error.rs | 9 +++++++++ src/model/guild/member.rs | 18 ++++++++++-------- src/model/guild/mod.rs | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) (limited to 'src/model') diff --git a/src/model/error.rs b/src/model/error.rs index 340bd18..a2b8325 100644 --- a/src/model/error.rs +++ b/src/model/error.rs @@ -86,6 +86,14 @@ pub enum Error { /// [`GuildId`]: ../model/struct.GuildId.html /// [`Cache`]: ../cache/struct.Cache.html GuildNotFound, + /// Indicates that there are hierarchy problems restricting an action. + /// + /// For example, when banning a user, if the other user has a role with an + /// equal to or higher position, then they can not be banned. + /// + /// When editing a role, if the role is higher in position than the current + /// user's highest role, then the role can not be edited. + Hierarchy, /// Indicates that you do not have the required permissions to perform an /// operation. /// @@ -126,6 +134,7 @@ impl StdError for Error { Error::DeleteMessageDaysAmount(_) => "Invalid delete message days", Error::EmbedTooLarge(_) => "Embed too large", Error::GuildNotFound => "Guild not found in the cache", + Error::Hierarchy => "Role hierarchy prevents this action", Error::InvalidPermissions(_) => "Invalid permissions", Error::InvalidUser => "The current user can not perform the action", Error::ItemMissing => "The required item is missing from the cache", diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 3622489..b93349e 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -309,16 +309,18 @@ impl Member { pub fn kick(&self) -> Result<()> { #[cfg(feature = "cache")] { - let req = Permissions::KICK_MEMBERS; + let cache = CACHE.read(); - let has_perms = CACHE - .read() - .guilds - .get(&self.guild_id) - .map(|guild| guild.read().has_perms(req)); + if let Some(guild) = self.guilds.get(&self.guild_id) { + let reader = guild.read(); + + if !guild.has_perms(req) { + let req = Permissions::KICK_MEMBERS; + + return Err(Error::Model(ModelError::InvalidPermissions(req))); + } - if let Some(false) = has_perms { - return Err(Error::Model(ModelError::InvalidPermissions(req))); + guild.check_hierarchy(&self.user.read().id)?; } } diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index f9eca59..c74b4b2 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -144,6 +144,19 @@ pub struct Guild { #[cfg(feature = "model")] impl Guild { + #[cfg(feature = "cache")] + fn check_hierarchy(&self, other_user: UserId) -> Result<()> { + let current_id = CACHE.read().user.id; + + if let Some(higher) = self.greater_member_hierarchy(user, current_id) { + if higher != current_id { + return Err(Error::Model(ModelError::Hierarchy)); + } + } + + Ok(()) + } + /// Returns the "default" channel of the guild for the passed user id. /// (This returns the first channel that can be read by the user, if there isn't one, /// returns `None`) @@ -215,6 +228,8 @@ impl Guild { /// [`User`]: struct.User.html /// [Ban Members]: permissions/constant.BAN_MEMBERS.html pub fn ban, BO: BanOptions>(&self, user: U, options: &BO) -> Result<()> { + let user = user.into(); + #[cfg(feature = "cache")] { let req = Permissions::BAN_MEMBERS; @@ -222,6 +237,8 @@ impl Guild { if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } + + self.check_hierarchy(user)?; } self.id.ban(user, options) -- cgit v1.2.3