Exemplo n.º 1
0
        public async ValueTask HandleLoggerBotCleanup(DiscordMessage msg)
        {
            if (msg.Channel.Type != ChannelType.Text)
            {
                return;
            }
            if (!msg.Channel.BotHasAllPermissions(Permissions.ManageMessages))
            {
                return;
            }

            // If this message is from a *webhook*, check if the name matches one of the bots we know
            // TODO: do we need to do a deeper webhook origin check, or would that be too hard on the rate limit?
            // If it's from a *bot*, check the bot ID to see if we know it.
            LoggerBot bot = null;

            if (msg.WebhookMessage)
            {
                _botsByWebhookName.TryGetValue(msg.Author.Username, out bot);
            }
            else if (msg.Author.IsBot)
            {
                _bots.TryGetValue(msg.Author.Id, out bot);
            }

            // If we didn't find anything before, or what we found is an unsupported bot, bail
            if (bot == null)
            {
                return;
            }

            try
            {
                // We try two ways of extracting the actual message, depending on the bots
                if (bot.FuzzyExtractFunc != null)
                {
                    // Some bots (Carl, Circle, etc) only give us a user ID and a rough timestamp, so we try our best to
                    // "cross-reference" those with the message DB. We know the deletion event happens *after* the message
                    // was sent, so we're checking for any messages sent in the same guild within 3 seconds before the
                    // delete event timestamp, which is... good enough, I think? Potential for false positives and negatives
                    // either way but shouldn't be too much, given it's constrained by user ID and guild.
                    var fuzzy = bot.FuzzyExtractFunc(msg);
                    if (fuzzy == null)
                    {
                        return;
                    }

                    using var conn = await _db.Obtain();

                    var mid = await conn.QuerySingleOrDefaultAsync <ulong?>(
                        "select mid from messages where sender = @User and mid > @ApproxID and guild = @Guild limit 1",
                        new
                    {
                        fuzzy.Value.User,
                        Guild    = msg.Channel.GuildId,
                        ApproxId = DiscordUtils.InstantToSnowflake(
                            fuzzy.Value.ApproxTimestamp - TimeSpan.FromSeconds(3))
                    });

                    if (mid == null)
                    {
                        return;              // If we didn't find a corresponding message, bail
                    }
                    // Otherwise, we can *reasonably assume* that this is a logged deletion, so delete the log message.
                    await msg.DeleteAsync();
                }
                else if (bot.ExtractFunc != null)
                {
                    // Other bots give us the message ID itself, and we can just extract that from the database directly.
                    var extractedId = bot.ExtractFunc(msg);
                    if (extractedId == null)
                    {
                        return;                      // If we didn't find anything, bail.
                    }
                    using var conn = await _db.Obtain();

                    // We do this through an inline query instead of through DataStore since we don't need all the joins it does
                    var mid = await conn.QuerySingleOrDefaultAsync <ulong?>(
                        "select mid from messages where original_mid = @Mid", new { Mid = extractedId.Value });

                    if (mid == null)
                    {
                        return;
                    }

                    // If we've gotten this far, we found a logged deletion of a trigger message. Just yeet it!
                    await msg.DeleteAsync();
                } // else should not happen, but idk, it might
            }
            catch (NotFoundException)
            {
                // Sort of a temporary measure: getting an error in Sentry about a NotFoundException from D#+ here
                // The only thing I can think of that'd cause this are the DeleteAsync() calls which 404 when
                // the message doesn't exist anyway - so should be safe to just ignore it, right?
            }
        }
Exemplo n.º 2
0
        public async ValueTask HandleLoggerBotCleanup(SocketMessage msg, GuildConfig cachedGuild)
        {
            // Bail if not enabled, or if we don't have permission here
            if (!cachedGuild.LogCleanupEnabled)
            {
                return;
            }
            if (!(msg.Channel is SocketTextChannel channel))
            {
                return;
            }
            if (!channel.Guild.GetUser(_client.CurrentUser.Id).GetPermissions(channel).ManageMessages)
            {
                return;
            }

            // If this message is from a *webhook*, check if the name matches one of the bots we know
            // TODO: do we need to do a deeper webhook origin check, or would that be too hard on the rate limit?
            // If it's from a *bot*, check the bot ID to see if we know it.
            LoggerBot bot = null;

            if (msg.Author.IsWebhook)
            {
                _botsByWebhookName.TryGetValue(msg.Author.Username, out bot);
            }
            else if (msg.Author.IsBot)
            {
                _bots.TryGetValue(msg.Author.Id, out bot);
            }

            // If we didn't find anything before, or what we found is an unsupported bot, bail
            if (bot == null)
            {
                return;
            }

            // We try two ways of extracting the actual message, depending on the bots
            if (bot.FuzzyExtractFunc != null)
            {
                // Some bots (Carl, Circle, etc) only give us a user ID and a rough timestamp, so we try our best to
                // "cross-reference" those with the message DB. We know the deletion event happens *after* the message
                // was sent, so we're checking for any messages sent in the same guild within 3 seconds before the
                // delete event timestamp, which is... good enough, I think? Potential for false positives and negatives
                // either way but shouldn't be too much, given it's constrained by user ID and guild.
                var fuzzy = bot.FuzzyExtractFunc(msg);
                if (fuzzy == null)
                {
                    return;
                }

                using var conn = await _db.Obtain();

                var mid = await conn.QuerySingleOrDefaultAsync <ulong?>(
                    "select mid from messages where sender = @User and mid > @ApproxID and guild = @Guild",
                    new
                {
                    fuzzy.Value.User,
                    Guild    = (msg.Channel as ITextChannel)?.GuildId ?? 0,
                    ApproxId = SnowflakeUtils.ToSnowflake(fuzzy.Value.ApproxTimestamp - TimeSpan.FromSeconds(3))
                });

                if (mid == null)
                {
                    return;              // If we didn't find a corresponding message, bail
                }
                // Otherwise, we can *reasonably assume* that this is a logged deletion, so delete the log message.
                await msg.DeleteAsync();
            }
            else if (bot.ExtractFunc != null)
            {
                // Other bots give us the message ID itself, and we can just extract that from the database directly.
                var extractedId = bot.ExtractFunc(msg);
                if (extractedId == null)
                {
                    return;                      // If we didn't find anything, bail.
                }
                using var conn = await _db.Obtain();

                // We do this through an inline query instead of through DataStore since we don't need all the joins it does
                var mid = await conn.QuerySingleOrDefaultAsync <ulong?>("select mid from messages where original_mid = @Mid", new { Mid = extractedId.Value });

                if (mid == null)
                {
                    return;
                }

                // If we've gotten this far, we found a logged deletion of a trigger message. Just yeet it!
                await msg.DeleteAsync();
            } // else should not happen, but idk, it might
        }