mirror of
https://github.com/dsec-hub/dsec-discord-bot.git
synced 2026-09-22 07:44:26 +00:00
COL-BOT-02: make the honeypot moderator guard fail safe
Codex review: the guard fell THROUGH to banning when the member lookup or the permission calculation failed, and it ignored per-channel permission overwrites. Now it computes effective permissions in the honeypot channel (honouring overwrites via Guild::user_permissions_in) and ABSTAINS from banning whenever the guild, the member, or the channel cannot be resolved — fail-safe: never ban when identity or permissions cannot be established. Replaces the deprecated Member::permissions call, so the #[allow(deprecated)] is gone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017XrE7F9ZuBWdQnS8CZvYDE
This commit is contained in:
parent
109de40d37
commit
74add2830d
1 changed files with 42 additions and 15 deletions
|
|
@ -1,6 +1,21 @@
|
||||||
use crate::{Data, Error, commands::mods_only::log_embed};
|
use crate::{Data, Error, commands::mods_only::log_embed};
|
||||||
use poise::serenity_prelude as serenity;
|
use poise::serenity_prelude as serenity;
|
||||||
|
|
||||||
|
/// Effective permissions for `member` in `channel_id`, honouring per-channel
|
||||||
|
/// permission overwrites. Returns `None` when the guild or the channel is not in
|
||||||
|
/// cache — the caller must treat that as "permissions could not be established"
|
||||||
|
/// and fail safe (do not ban), never as "no permissions".
|
||||||
|
fn channel_permissions(
|
||||||
|
ctx: &serenity::Context,
|
||||||
|
guild_id: serenity::GuildId,
|
||||||
|
channel_id: serenity::ChannelId,
|
||||||
|
member: &serenity::Member,
|
||||||
|
) -> Option<serenity::Permissions> {
|
||||||
|
let guild = ctx.cache.guild(guild_id)?;
|
||||||
|
let channel = guild.channels.get(&channel_id)?;
|
||||||
|
Some(guild.user_permissions_in(channel, member))
|
||||||
|
}
|
||||||
|
|
||||||
async fn honeypot(
|
async fn honeypot(
|
||||||
ctx: &serenity::Context,
|
ctx: &serenity::Context,
|
||||||
new_message: &serenity::Message,
|
new_message: &serenity::Message,
|
||||||
|
|
@ -20,23 +35,35 @@ async fn honeypot(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never ban someone who can moderate. A moderator checking whether the
|
// Never ban someone who can moderate, and fail SAFE: whenever the author's
|
||||||
// honeypot works should not be the person it catches. This reads the
|
// identity or permissions cannot be established, abstain rather than ban.
|
||||||
// cached guild; if it is unavailable we fall through and let the honeypot
|
// A honeypot that occasionally misses a spammer is far cheaper than one
|
||||||
// act, rather than skipping the check silently for everyone.
|
// that bans a moderator or a legitimate member.
|
||||||
if let Some(guild_id) = new_message.guild_id
|
let Some(message_guild_id) = new_message.guild_id else {
|
||||||
&& let Ok(member) = guild_id.member(ctx, user.id).await
|
eprintln!("[honeypot] message has no guild_id; abstaining from ban");
|
||||||
{
|
return Ok(());
|
||||||
// Guild-level moderator identity is exactly what we want here; the
|
};
|
||||||
// deprecation is about per-channel permission overwrites, which are
|
let member = match message_guild_id.member(ctx, user.id).await {
|
||||||
// irrelevant to "can this person moderate at all".
|
Ok(member) => member,
|
||||||
#[allow(deprecated)]
|
Err(err) => {
|
||||||
let perms = member.permissions(ctx);
|
eprintln!(
|
||||||
if let Ok(perms) = perms
|
"[honeypot] could not fetch member {} to check permissions; abstaining: {err}",
|
||||||
&& (perms.ban_members() || perms.manage_messages() || perms.administrator())
|
user.id
|
||||||
{
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
// Effective permissions IN THE HONEYPOT CHANNEL (honouring overwrites).
|
||||||
|
let Some(perms) = channel_permissions(ctx, message_guild_id, *current_channel_id, &member)
|
||||||
|
else {
|
||||||
|
eprintln!(
|
||||||
|
"[honeypot] could not compute permissions for {} in {}; abstaining",
|
||||||
|
user.id, current_channel_id
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
if perms.ban_members() || perms.manage_messages() || perms.administrator() {
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let username = &user.name;
|
let username = &user.name;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue