diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b3f8cdb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + allow: + # Allow both direct and indirect updates for all packages + - dependency-type: "all" + assignees: + - "l1ttleO" + + - package-ecosystem: "nuget" # See documentation for possible values + directory: "/Boyfriend" # Location of package manifests + schedule: + interval: "weekly" + allow: + # Allow both direct and indirect updates for all packages + - dependency-type: "all" + # Add assignees + assignees: + - "l1ttleO" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..4bd4390 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,44 @@ +name: "CodeQL" + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + schedule: + - cron: '45 7 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'csharp' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + queries: +security-extended,security-and-quality + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/Boyfriend/Boyfriend.cs b/Boyfriend/Boyfriend.cs index df38768..b0ec6ce 100644 --- a/Boyfriend/Boyfriend.cs +++ b/Boyfriend/Boyfriend.cs @@ -83,7 +83,7 @@ public static class Boyfriend { if (!RemovedRolesDictionary.ContainsKey(id)) RemovedRolesDictionary.Add(id, new Dictionary>()); - if (GuildConfigDictionary.ContainsKey(id)) return GuildConfigDictionary[id]; + if (GuildConfigDictionary.TryGetValue(id, out var cfg)) return cfg; var path = $"config_{id}.json"; @@ -110,7 +110,7 @@ public static class Boyfriend { } public static Dictionary> GetRemovedRoles(ulong id) { - if (RemovedRolesDictionary.ContainsKey(id)) return RemovedRolesDictionary[id]; + if (RemovedRolesDictionary.TryGetValue(id, out var dict)) return dict; var path = $"removedroles_{id}.json"; @@ -126,7 +126,7 @@ public static class Boyfriend { } public static SocketGuild FindGuild(ulong channel) { - if (GuildCache.ContainsKey(channel)) return GuildCache[channel]; + if (GuildCache.TryGetValue(channel, out var gld)) return gld; foreach (var guild in Client.Guilds) { // ReSharper disable once LoopCanBeConvertedToQuery foreach (var x in guild.Channels) diff --git a/Boyfriend/Boyfriend.csproj b/Boyfriend/Boyfriend.csproj index a578853..c5000cb 100644 --- a/Boyfriend/Boyfriend.csproj +++ b/Boyfriend/Boyfriend.csproj @@ -8,11 +8,11 @@ default Boyfriend l1ttle - https://git.cavej376.xyz/Octol1ttle/Boyfriend-CSharp - https://git.cavej376.xyz/Octol1ttle/Boyfriend-CSharp + https://github.com/l1ttleO/Boyfriend-CSharp + https://github.com/l1ttleO/Boyfriend-CSharp git - 1.0.1 - https://git.cavej376.xyz/Octol1ttle/Boyfriend-CSharp/src/branch/master/LICENSE + 1.0.0 + https://github.com/l1ttleO/Boyfriend-CSharp/blob/master/LICENSE en diff --git a/Boyfriend/CommandProcessor.cs b/Boyfriend/CommandProcessor.cs index c4cfbc1..06bbe2e 100644 --- a/Boyfriend/CommandProcessor.cs +++ b/Boyfriend/CommandProcessor.cs @@ -1,5 +1,4 @@ using System.Text; -using System.Text.RegularExpressions; using Boyfriend.Commands; using Discord; using Discord.Commands; @@ -14,14 +13,14 @@ public sealed class CommandProcessor { private const string NoAccess = ":no_entry_sign: "; private const string CantInteract = ":vertical_traffic_light: "; + private const string Mention = "<@855023234407333888>"; + public static readonly ICommand[] Commands = { new BanCommand(), new ClearCommand(), new HelpCommand(), new KickCommand(), new MuteCommand(), new PingCommand(), new SettingsCommand(), new UnbanCommand(), new UnmuteCommand() }; - private static readonly Dictionary RegexCache = new(); - private static readonly Regex MentionRegex = new(Regex.Escape("<@855023234407333888>"), RegexOptions.Compiled); private readonly StringBuilder _stackedPrivateFeedback = new(); private readonly StringBuilder _stackedPublicFeedback = new(); private readonly StringBuilder _stackedReplyMessage = new(); @@ -46,16 +45,10 @@ public sealed class CommandProcessor { return; } - Regex regex; - if (RegexCache.ContainsKey(config["Prefix"])) { regex = RegexCache[config["Prefix"]]; } else { - regex = new Regex(Regex.Escape(config["Prefix"]), RegexOptions.Compiled | RegexOptions.IgnoreCase); - RegexCache.Add(config["Prefix"], regex); - } - var list = Context.Message.Content.Split("\n"); var cleanList = Context.Message.CleanContent.Split("\n"); for (var i = 0; i < list.Length; i++) { - RunCommandOnLine(list[i], cleanList[i], regex); + RunCommandOnLine(list[i], cleanList[i], config["Prefix"]); if (_serverBlacklisted) { await Context.Message.ReplyAsync(Messages.ServerBlacklisted); return; @@ -78,20 +71,21 @@ public sealed class CommandProcessor { SendFeedbacks(); } - private void RunCommandOnLine(string line, string cleanLine, Regex regex) { + private void RunCommandOnLine(string line, string cleanLine, string prefix) { + var prefixed = line[..prefix.Length] == prefix; + if (!prefixed && line[..Mention.Length] is not Mention) return; foreach (var command in Commands) { - var lineNoMention = regex.Replace(MentionRegex.Replace(line, "", 1), "", 1); - if (lineNoMention == line - || !command.Aliases.Contains(lineNoMention.Trim().ToLower().Split()[0])) - continue; + var lineNoMention = line.Remove(0, prefixed ? prefix.Length : Mention.Length); + if (!command.Aliases.Contains(lineNoMention.Trim().Split()[0])) continue; if (Utils.IsServerBlacklisted(Context.Guild)) { _serverBlacklisted = true; return; } - var args = line.Split().Skip(lineNoMention.StartsWith(" ") ? 2 : 1).ToArray(); + var args = lineNoMention.Trim().Split().Skip(1).ToArray(); var cleanArgs = cleanLine.Split().Skip(lineNoMention.StartsWith(" ") ? 2 : 1).ToArray(); _tasks.Add(command.RunAsync(this, args, cleanArgs)); + return; } } diff --git a/Boyfriend/Commands/MuteCommand.cs b/Boyfriend/Commands/MuteCommand.cs index 998c65e..bc608f9 100644 --- a/Boyfriend/Commands/MuteCommand.cs +++ b/Boyfriend/Commands/MuteCommand.cs @@ -26,8 +26,8 @@ public sealed class MuteCommand : ICommand { var rolesRemoved = Boyfriend.GetRemovedRoles(cmd.Context.Guild.Id); - if (rolesRemoved.ContainsKey(toMute.Id)) { - foreach (var roleId in rolesRemoved[toMute.Id]) await toMute.AddRoleAsync(roleId); + if (rolesRemoved.TryGetValue(toMute.Id, out var mutedRemovedRoles)) { + foreach (var roleId in mutedRemovedRoles) await toMute.AddRoleAsync(roleId); rolesRemoved.Remove(toMute.Id); cmd.ConfigWriteScheduled = true; cmd.Reply(Messages.RolesReturned, ":warning: "); diff --git a/Boyfriend/Commands/SettingsCommand.cs b/Boyfriend/Commands/SettingsCommand.cs index 8738972..da71579 100644 --- a/Boyfriend/Commands/SettingsCommand.cs +++ b/Boyfriend/Commands/SettingsCommand.cs @@ -110,10 +110,9 @@ public sealed class SettingsCommand : ICommand { }; if (value is "reset" or "default") { - if (selectedSetting is "WelcomeMessage") - config[selectedSetting] = Messages.DefaultWelcomeMessage; - else - config[selectedSetting] = Boyfriend.DefaultConfig[selectedSetting]; + config[selectedSetting] = selectedSetting is "WelcomeMessage" + ? Messages.DefaultWelcomeMessage + : Boyfriend.DefaultConfig[selectedSetting]; } else { if (value == config[selectedSetting]) { cmd.Reply(string.Format(Messages.SettingsNothingChanged, localizedSelectedSetting, formattedValue), diff --git a/Boyfriend/Commands/UnmuteCommand.cs b/Boyfriend/Commands/UnmuteCommand.cs index 8297830..b6a1aa9 100644 --- a/Boyfriend/Commands/UnmuteCommand.cs +++ b/Boyfriend/Commands/UnmuteCommand.cs @@ -23,8 +23,8 @@ public sealed class UnmuteCommand : ICommand { if (role != null && toUnmute.Roles.Contains(role)) { var rolesRemoved = Boyfriend.GetRemovedRoles(cmd.Context.Guild.Id); - if (rolesRemoved.ContainsKey(toUnmute.Id)) { - await toUnmute.AddRolesAsync(rolesRemoved[toUnmute.Id]); + if (rolesRemoved.TryGetValue(toUnmute.Id, out var unmutedRemovedRoles)) { + await toUnmute.AddRolesAsync(unmutedRemovedRoles); rolesRemoved.Remove(toUnmute.Id); cmd.ConfigWriteScheduled = true; } diff --git a/Boyfriend/Utils.cs b/Boyfriend/Utils.cs index fa2c29d..85114a8 100644 --- a/Boyfriend/Utils.cs +++ b/Boyfriend/Utils.cs @@ -65,7 +65,7 @@ public static class Utils { public static SocketRole? GetMuteRole(SocketGuild guild) { var id = ulong.Parse(Boyfriend.GetGuildConfig(guild.Id)["MuteRole"]); - if (MuteRoleCache.ContainsKey(id)) return MuteRoleCache[id]; + if (MuteRoleCache.TryGetValue(id, out var cachedMuteRole)) return cachedMuteRole; SocketRole? role = null; foreach (var x in guild.Roles) { if (x.Id != id) continue; @@ -88,7 +88,6 @@ public static class Utils { await channel.SendMessageAsync(text, false, null, null, allowRoles ? AllowRoles : AllowedMentions.None); } - public static RequestOptions GetRequestOptions(string reason) { var options = RequestOptions.Default; options.AuditLogReason = reason; @@ -98,7 +97,7 @@ public static class Utils { public static string GetMessage(string name) { var propertyName = name; name = $"{Messages.Culture}/{name}"; - if (ReflectionMessageCache.ContainsKey(name)) return ReflectionMessageCache[name]; + if (ReflectionMessageCache.TryGetValue(name, out var cachedMessage)) return cachedMessage; var toReturn = typeof(Messages).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null)