Esempio n. 1
0
        static async Task MainAsync(string[] _)
        {
            var json = "";

            using (var fs = File.OpenRead("config.json"))
                using (var sr = new StreamReader(fs, new UTF8Encoding(false)))
                    json = await sr.ReadToEndAsync();

            cfgjson = JsonConvert.DeserializeObject <ConfigJson>(json);

            var keys = cfgjson.WordListList.Keys;

            foreach (string key in keys)
            {
                var listOutput = File.ReadAllLines($"Lists/{key}");
                cfgjson.WordListList[key].Words = listOutput;
            }

            string redisHost;

            if (Environment.GetEnvironmentVariable("REDIS_DOCKER_OVERRIDE") != null)
            {
                redisHost = "redis";
            }
            else
            {
                redisHost = cfgjson.Redis.Host;
            }
            redis = ConnectionMultiplexer.Connect($"{redisHost}:{cfgjson.Redis.Port}");
            db    = redis.GetDatabase();
            db.KeyDelete("messages");

            discord = new DiscordClient(new DiscordConfiguration
            {
                Token           = cfgjson.Core.Token,
                TokenType       = TokenType.Bot,
                MinimumLogLevel = Microsoft.Extensions.Logging.LogLevel.Debug,
                Intents         = DiscordIntents.All
            });

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            async Task OnReady(DiscordClient client, ReadyEventArgs e)
            {
                Console.WriteLine($"Logged in as {client.CurrentUser.Username}#{client.CurrentUser.Discriminator}");
                logChannel = await discord.GetChannelAsync(cfgjson.LogChannel);

                Mutes.CheckMutesAsync();
                ModCmds.CheckBansAsync();
            }

            async Task MessageCreated(DiscordClient client, MessageCreateEventArgs e)
            {
                if (e.Channel.IsPrivate || e.Guild.Id != cfgjson.ServerID || e.Author.IsBot)
                {
                    return;
                }

                if (processedMessages.Contains(e.Message.Id))
                {
                    return;
                }
                else
                {
                    processedMessages.Add(e.Message.Id);
                }

                DiscordMember member = await e.Guild.GetMemberAsync(e.Author.Id);

                if (Warnings.GetPermLevel(member) >= ServerPermLevel.TrialMod)
                {
                    return;
                }


                bool match = false;

                // Matching word list
                var wordListKeys = cfgjson.WordListList.Keys;

                foreach (string key in wordListKeys)
                {
                    if (CheckForNaughtyWords(e.Message.Content, cfgjson.WordListList[key]))
                    {
                        try
                        {
                            e.Message.DeleteAsync();
                            DiscordChannel logChannel = await discord.GetChannelAsync(Program.cfgjson.LogChannel);

                            var embed = new DiscordEmbedBuilder()
                                        .WithDescription(e.Message.Content)
                                        .WithColor(new DiscordColor(0xf03916))
                                        .WithTimestamp(e.Message.Timestamp)
                                        .WithFooter(
                                $"User ID: {e.Author.Id}",
                                null
                                )
                                        .WithAuthor(
                                $"{e.Author.Username}#{e.Author.Discriminator} in #{e.Channel.Name}",
                                null,
                                e.Author.AvatarUrl
                                );
                            logChannel.SendMessageAsync($"{cfgjson.Emoji.Denied} Deleted infringing message by {e.Author.Mention} in {e.Channel.Mention}:", false, embed);
                        }
                        catch
                        {
                            // still warn anyway
                        }

                        match = true;
                        string         reason = cfgjson.WordListList[key].Reason;
                        DiscordMessage msg    = await e.Channel.SendMessageAsync($"{cfgjson.Emoji.Denied} {e.Message.Author.Mention} was warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                        Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink: Warnings.MessageLink(msg), e.Channel);
                        return;
                    }
                    if (match)
                    {
                        return;
                    }
                }

                if (match)
                {
                    return;
                }

                // Mass emoji
                if (e.Message.MentionedUsers.Count >= cfgjson.MassMentionThreshold)
                {
                    DiscordChannel logChannel = await discord.GetChannelAsync(Program.cfgjson.LogChannel);

                    try
                    {
                        e.Message.DeleteAsync();
                        var embed = new DiscordEmbedBuilder()
                                    .WithDescription(e.Message.Content)
                                    .WithColor(new DiscordColor(0xf03916))
                                    .WithTimestamp(e.Message.Timestamp)
                                    .WithFooter(
                            $"User ID: {e.Author.Id}",
                            null
                            )
                                    .WithAuthor(
                            $"{e.Author.Username}#{e.Author.Discriminator} in #{e.Channel.Name}",
                            null,
                            e.Author.AvatarUrl
                            );
                        logChannel.SendMessageAsync($"{cfgjson.Emoji.Denied} Deleted infringing message by {e.Author.Mention} in {e.Channel.Mention}:", false, embed);
                    }
                    catch
                    {
                        // still warn anyway
                    }

                    string         reason = "Mass mentions";
                    DiscordMessage msg    = await e.Channel.SendMessageAsync($"{cfgjson.Emoji.Denied} {e.Message.Author.Mention} was warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                    await Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink : Warnings.MessageLink(msg), e.Channel);

                    return;
                }

                // Unapproved invites
                if (Warnings.GetPermLevel(member) < (ServerPermLevel)cfgjson.InviteTierRequirement)
                {
                    string inviteExclusion = "microsoft";
                    if (cfgjson.InviteExclusion != null)
                    {
                        inviteExclusion = cfgjson.InviteExclusion;
                    }

                    string checkedMessage = e.Message.Content.Replace($"discord.gg/{inviteExclusion}", "").Replace($"discord.com/invite/{inviteExclusion}", "");

                    if (checkedMessage.Contains("discord.gg/") || checkedMessage.Contains("discord.com/invite/"))
                    {
                        try
                        {
                            e.Message.DeleteAsync();
                            var embed = new DiscordEmbedBuilder()
                                        .WithDescription(e.Message.Content)
                                        .WithColor(new DiscordColor(0xf03916))
                                        .WithTimestamp(e.Message.Timestamp)
                                        .WithFooter(
                                $"User ID: {e.Author.Id}",
                                null
                                )
                                        .WithAuthor(
                                $"{e.Author.Username}#{e.Author.Discriminator} in #{e.Channel.Name}",
                                null,
                                e.Author.AvatarUrl
                                );
                            logChannel.SendMessageAsync($"{cfgjson.Emoji.Denied} Deleted infringing message by {e.Author.Mention} in {e.Channel.Mention}:", false, embed);
                        }
                        catch
                        {
                            // still warn anyway
                        }
                        string         reason = "Sent an invite";
                        DiscordMessage msg    = await e.Channel.SendMessageAsync($"{Program.cfgjson.Emoji.Denied} {e.Message.Author.Mention} was warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                        await Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink : Warnings.MessageLink(msg), e.Channel);

                        return;
                    }
                }

                // Mass emoji
                if (!cfgjson.UnrestrictedEmojiChannels.Contains(e.Message.ChannelId) && e.Message.Content.Length >= cfgjson.MassEmojiThreshold)
                {
                    char[] tempArray = e.Message.Content.Replace("🏻", "").Replace("🏼", "").Replace("🏽", "").Replace("🏾", "").Replace("🏿", "").ToCharArray();
                    int    pos       = 0;
                    foreach (char c in tempArray)
                    {
                        if (c == '™' || c == '®' || c == '©')
                        {
                            tempArray[pos] = ' ';
                        }
                        if (c == '\u200d')
                        {
                            tempArray[pos]     = ' ';
                            tempArray[pos + 1] = ' ';
                        }
                        ++pos;
                    }
                    string input = new string(tempArray);

                    var matches = emoji_rx.Matches(input);
                    if (matches.Count > cfgjson.MassEmojiThreshold)
                    {
                        e.Message.DeleteAsync();
                        string         reason = "Mass emoji";
                        DiscordMessage msg    = await e.Channel.SendMessageAsync($"{Program.cfgjson.Emoji.Denied} {e.Message.Author.Mention} was warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                        await Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink : Warnings.MessageLink(msg), e.Channel);

                        return;
                    }
                }
            }

            async Task GuildMemberAdded(DiscordClient client, GuildMemberAddEventArgs e)
            {
                if (e.Guild.Id != cfgjson.ServerID)
                {
                    return;
                }

                if (await db.HashExistsAsync("mutes", e.Member.Id))
                {
                    // todo: store per-guild
                    DiscordRole mutedRole = e.Guild.GetRole(cfgjson.MutedRole);
                    await e.Member.GrantRoleAsync(mutedRole);
                }
            }

            discord.Ready            += OnReady;
            discord.MessageCreated   += MessageCreated;
            discord.GuildMemberAdded += GuildMemberAdded;


            commands = discord.UseCommandsNext(new CommandsNextConfiguration
            {
                StringPrefixes = cfgjson.Core.Prefixes
            });;

            commands.RegisterCommands <Warnings>();
            commands.RegisterCommands <MuteCmds>();
            commands.RegisterCommands <UserRoleCmds>();
            commands.RegisterCommands <ModCmds>();

            await discord.ConnectAsync();

            while (true)
            {
                await Task.Delay(60000);

                Mutes.CheckMutesAsync();
                ModCmds.CheckBansAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }
        }
Esempio n. 2
0
        static async Task MainAsync(string[] _)
        {
            string token;
            var    json = "";

            string configFile = "config.json";

#if DEBUG
            configFile = "config.dev.json";
#endif

            using (var fs = File.OpenRead(configFile))
                using (var sr = new StreamReader(fs, new UTF8Encoding(false)))
                    json = await sr.ReadToEndAsync();

            cfgjson = JsonConvert.DeserializeObject <ConfigJson>(json);

            var keys = cfgjson.WordListList.Keys;
            foreach (string key in keys)
            {
                var listOutput = File.ReadAllLines($"Lists/{key}");
                cfgjson.WordListList[key].Words = listOutput;
            }

            if (Environment.GetEnvironmentVariable("FORTEBASS_TOKEN") != null)
            {
                token = Environment.GetEnvironmentVariable("FORTEBASS_TOKEN");
            }
            else
            {
                token = cfgjson.Core.Token;
            }

            string redisHost;
            if (Environment.GetEnvironmentVariable("REDIS_DOCKER_OVERRIDE") != null)
            {
                redisHost = "redis";
            }
            else
            {
                redisHost = cfgjson.Redis.Host;
            }
            redis = ConnectionMultiplexer.Connect($"{redisHost}:{cfgjson.Redis.Port}");
            db    = redis.GetDatabase();
            db.KeyDelete("messages");

            discord = new DiscordClient(new DiscordConfiguration
            {
                Token           = token,
                TokenType       = TokenType.Bot,
                MinimumLogLevel = Microsoft.Extensions.Logging.LogLevel.Debug,
                Intents         = DiscordIntents.All
            });


#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            async Task OnReady(DiscordClient client, ReadyEventArgs e)
            {
                Console.WriteLine($"Logged in as {client.CurrentUser.Username}#{client.CurrentUser.Discriminator}");
                logChannel = await discord.GetChannelAsync(cfgjson.LogChannel);

                Mutes.CheckMutesAsync();
                ModCmds.CheckBansAsync();
                ModCmds.CheckRemindersAsync();

                string commitHash    = "aaaaaaa";
                string commitMessage = "N/A";
                string commitTime    = "0000-00-00 00:00:00 +0000";

                if (File.Exists("CommitHash.txt"))
                {
                    using var sr = new StreamReader("CommitHash.txt");
                    commitHash   = sr.ReadToEnd();
                }

                if (File.Exists("CommitMessage.txt"))
                {
                    using var sr  = new StreamReader("CommitMessage.txt");
                    commitMessage = sr.ReadToEnd();
                }

                if (File.Exists("CommitTime.txt"))
                {
                    using var sr = new StreamReader("CommitTime.txt");
                    commitTime   = sr.ReadToEnd();
                }

                var FortebassChannel = await client.GetChannelAsync(cfgjson.HomeChannel);

                FortebassChannel.SendMessageAsync($"{cfgjson.Emoji.Connected} Fortebass connected successfully!\n\n" +
                                                  $"**Version**: `{commitHash}`\n" +
                                                  $"**Version timestamp**: `{commitTime}`\n**Framework**: `{RuntimeInformation.FrameworkDescription}`\n**Platform**: `{RuntimeInformation.OSDescription}`\n\n" +
                                                  $"Most recent commit message:\n" +
                                                  $"```\n" +
                                                  $"{commitMessage}\n" +
                                                  $"```");
            }

            async Task MessageCreated(DiscordClient client, MessageCreateEventArgs e)
            {
                if (e.Channel.IsPrivate || e.Guild.Id != cfgjson.ServerID || e.Author.IsBot)
                {
                    return;
                }

                if (processedMessages.Contains(e.Message.Id))
                {
                    return;
                }
                else
                {
                    processedMessages.Add(e.Message.Id);
                }

                DiscordMember member = await e.Guild.GetMemberAsync(e.Author.Id);

                if (Warnings.GetPermLevel(member) >= ServerPermLevel.CommunityManager)
                {
                    return;
                }


                bool match = false;

                // Matching word list
                var wordListKeys = cfgjson.WordListList.Keys;

                foreach (string key in wordListKeys)
                {
                    if (CheckForNaughtyWords(e.Message.Content.ToLower(), cfgjson.WordListList[key]))
                    {
                        try
                        {
                            e.Message.DeleteAsync();
                            DiscordChannel logChannel = await discord.GetChannelAsync(Program.cfgjson.LogChannel);

                            var embed = new DiscordEmbedBuilder()
                                        .WithDescription(e.Message.Content)
                                        .WithColor(new DiscordColor(0xf03916))
                                        .WithTimestamp(e.Message.Timestamp)
                                        .WithFooter(
                                $"User ID: {e.Author.Id}",
                                null
                                )
                                        .WithAuthor(
                                $"{e.Author.Username}#{e.Author.Discriminator} in #{e.Channel.Name}",
                                null,
                                e.Author.AvatarUrl
                                );
                            logChannel.SendMessageAsync($"{cfgjson.Emoji.Denied} Deleted infringing message by {e.Author.Mention} in {e.Channel.Mention}:", embed);
                        }
                        catch
                        {
                            // still warn anyway
                        }

                        match = true;
                        string         reason = cfgjson.WordListList[key].Reason;
                        DiscordMessage msg    = await e.Channel.SendMessageAsync($"{cfgjson.Emoji.Denied} {e.Message.Author.Mention} was automatically warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                        Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink: Warnings.MessageLink(msg), e.Channel);
                        return;
                    }
                    if (match)
                    {
                        return;
                    }
                }

                if (match)
                {
                    return;
                }

                // Mass mentions
                if (e.Message.MentionedUsers.Count >= cfgjson.MassMentionThreshold && Warnings.GetPermLevel(member) < ServerPermLevel.Mod)
                {
                    DiscordChannel logChannel = await discord.GetChannelAsync(cfgjson.LogChannel);

                    try
                    {
                        e.Message.DeleteAsync();
                        var embed = new DiscordEmbedBuilder()
                                    .WithDescription(e.Message.Content)
                                    .WithColor(new DiscordColor(0xf03916))
                                    .WithTimestamp(e.Message.Timestamp)
                                    .WithFooter(
                            $"User ID: {e.Author.Id}",
                            null
                            )
                                    .WithAuthor(
                            $"{e.Author.Username}#{e.Author.Discriminator} in #{e.Channel.Name}",
                            null,
                            e.Author.AvatarUrl
                            );
                        logChannel.SendMessageAsync($"{cfgjson.Emoji.Denied} Deleted infringing message by {e.Author.Mention} in {e.Channel.Mention}:", embed);
                    }
                    catch
                    {
                        // still warn anyway
                    }

                    string         reason = "Mass mentions";
                    DiscordMessage msg    = await e.Channel.SendMessageAsync($"{cfgjson.Emoji.Denied} {e.Message.Author.Mention} was automatically warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                    await Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink : Warnings.MessageLink(msg), e.Channel);

                    return;
                }

                // Unapproved invites
                if (Warnings.GetPermLevel(member) < (ServerPermLevel)cfgjson.InviteTierRequirement)
                {
                    string inviteExclusion = cfgjson.InviteExclusion;
                    if (cfgjson.InviteExclusion != null)
                    {
                        inviteExclusion = cfgjson.InviteExclusion;
                    }

                    string checkedMessage = e.Message.Content.Replace($"discord.gg/{inviteExclusion}", "").Replace($"discord.com/invite/{inviteExclusion}", "").Replace('\\', '/');

                    if (checkedMessage.Contains("discord.gg/") || checkedMessage.Contains("discord.com/invite/"))
                    {
                        try
                        {
                            e.Message.DeleteAsync();
                            var embed = new DiscordEmbedBuilder()
                                        .WithDescription(e.Message.Content)
                                        .WithColor(new DiscordColor(0xf03916))
                                        .WithTimestamp(e.Message.Timestamp)
                                        .WithFooter(
                                $"User ID: {e.Author.Id}",
                                null
                                )
                                        .WithAuthor(
                                $"{e.Author.Username}#{e.Author.Discriminator} in #{e.Channel.Name}",
                                null,
                                e.Author.AvatarUrl
                                );
                            logChannel.SendMessageAsync($"{cfgjson.Emoji.Denied} Deleted infringing message by {e.Author.Mention} in {e.Channel.Mention}:", embed);
                        }
                        catch
                        {
                            // still warn anyway
                        }
                        string         reason = "Sent an invite";
                        DiscordMessage msg    = await e.Channel.SendMessageAsync($"{Program.cfgjson.Emoji.Denied} {e.Message.Author.Mention} was automatically warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**");

                        await Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink : Warnings.MessageLink(msg), e.Channel);

                        return;
                    }
                }

                // Mass emoji
                if (!cfgjson.UnrestrictedEmojiChannels.Contains(e.Message.ChannelId) && e.Message.Content.Length >= cfgjson.MassEmojiThreshold)
                {
                    char[] tempArray = e.Message.Content.Replace("🏻", "").Replace("🏼", "").Replace("🏽", "").Replace("🏾", "").Replace("🏿", "").ToCharArray();
                    int    pos       = 0;
                    foreach (char c in tempArray)
                    {
                        if (c == '™' || c == '®' || c == '©')
                        {
                            tempArray[pos] = ' ';
                        }
                        if (c == '\u200d')
                        {
                            tempArray[pos]     = ' ';
                            tempArray[pos + 1] = ' ';
                        }
                        ++pos;
                    }
                    string input = new string(tempArray);

                    var matches = emoji_rx.Matches(input);
                    if (matches.Count > cfgjson.MassEmojiThreshold)
                    {
                        e.Message.DeleteAsync();

                        if (Warnings.GetPermLevel(member) == ServerPermLevel.nothing && !db.HashExists("emojiPardoned", e.Message.Author.Id.ToString()))
                        {
                            await db.HashSetAsync("emojiPardoned", member.Id.ToString(), false);

                            await e.Channel.SendMessageAsync($"{cfgjson.Emoji.Information} {e.Author.Mention}, if you want to play around with lots of emoji, please use <#{cfgjson.UnrestrictedEmojiChannels[0]}> to avoid punishment.");

                            return;
                        }

                        string reason = "Mass emoji";
                        string output = $"{Program.cfgjson.Emoji.Denied} {e.Message.Author.Mention} was automatically warned: **{reason.Replace("`", "\\`").Replace("*", "\\*")}**";
                        if (!db.HashExists("emojiPardoned", e.Author.Id.ToString()) || db.HashGet("emojiPardoned", e.Message.Author.Id.ToString()) == false)
                        {
                            output += $"\nIf you want to play around with lots of emoji, please use <#{cfgjson.UnrestrictedEmojiChannels[0]}> to avoid punishment.";
                            await db.HashSetAsync("emojiPardoned", member.Id.ToString(), true);
                        }

                        DiscordMessage msg = await e.Channel.SendMessageAsync(output);

                        await Warnings.GiveWarningAsync(e.Message.Author, discord.CurrentUser, reason, contextLink : Warnings.MessageLink(msg), e.Channel);

                        return;
                    }
                }
            }

            async Task GuildMemberAdded(DiscordClient client, GuildMemberAddEventArgs e)
            {
                if (e.Guild.Id != cfgjson.ServerID)
                {
                    return;
                }

                if (await db.HashExistsAsync("mutes", e.Member.Id))
                {
                    // todo: store per-guild
                    DiscordRole mutedRole = e.Guild.GetRole(cfgjson.MutedRole);
                    await e.Member.GrantRoleAsync(mutedRole, "Reapplying mute: possible mute evasion.");
                }
            }

            discord.Ready                += OnReady;
            discord.MessageCreated       += MessageCreated;
            discord.GuildMemberAdded     += GuildMemberAdded;
            discord.MessageReactionAdded += OnReaction;

            commands = discord.UseCommandsNext(new CommandsNextConfiguration
            {
                StringPrefixes = cfgjson.Core.Prefixes
            });;

            commands.RegisterCommands <Warnings>();
            commands.RegisterCommands <MuteCmds>();
            commands.RegisterCommands <UserRoleCmds>();
            commands.RegisterCommands <ModCmds>();

            await discord.ConnectAsync();

            while (true)
            {
                await Task.Delay(10000);

                Mutes.CheckMutesAsync();
                ModCmds.CheckBansAsync();
                ModCmds.CheckRemindersAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }
        }