public async Task Update(CommandContext ctx, [RemainingText, Description("An invite link or an invite token")] string invite) { var(_, _, invites) = await ctx.Client.GetInvitesAsync(invite, tryMessageAsACode : true).ConfigureAwait(false); if (invites.Count == 0) { await ctx.ReactWithAsync(Config.Reactions.Failure, "Need to specify an invite link or token").ConfigureAwait(false); return; } var errors = 0; foreach (var i in invites) { if (!await InviteWhitelistProvider.IsWhitelistedAsync(i).ConfigureAwait(false)) { errors++; } } if (errors == 0) { await ctx.ReactWithAsync(Config.Reactions.Success, "Invite whitelist was successfully updated!").ConfigureAwait(false); } else { await ctx.ReactWithAsync(Config.Reactions.Failure, $"Failed to update {errors} invite{StringUtils.GetSuffix(errors)}").ConfigureAwait(false); } await List(ctx).ConfigureAwait(false); }
public async Task Remove(CommandContext ctx, [Description("Filter IDs to remove, separated with spaces")] params int[] ids) { var failedIds = new List <int>(); foreach (var id in ids) { if (!await InviteWhitelistProvider.RemoveAsync(id).ConfigureAwait(false)) { failedIds.Add(id); } } if (failedIds.Count > 0) { await ctx.Channel.SendMessageAsync("Some IDs couldn't be removed: " + string.Join(", ", failedIds)).ConfigureAwait(false); } else { await ctx.ReactWithAsync(Config.Reactions.Success, $"Invite{StringUtils.GetSuffix(ids.Length)} successfully removed!").ConfigureAwait(false); } await List(ctx).ConfigureAwait(false); }
public async Task Add(CommandContext ctx, [Description("A Discord server IDs to whitelist")] params ulong[] guildIds) { var errors = 0; foreach (var guildId in guildIds) { if (!await InviteWhitelistProvider.AddAsync(guildId).ConfigureAwait(false)) { errors++; } } if (errors == 0) { await ctx.ReactWithAsync(Config.Reactions.Success, "Invite whitelist was successfully updated!").ConfigureAwait(false); } else { await ctx.ReactWithAsync(Config.Reactions.Failure, $"Failed to add {errors} invite{StringUtils.GetSuffix(errors)} to the whitelist").ConfigureAwait(false); } }
internal static async Task Main(string[] args) { Config.TelemetryClient?.TrackEvent("startup"); Console.WriteLine("Confinement: " + SandboxDetector.Detect()); if (args.Length > 0 && args[0] == "--dry-run") { Console.WriteLine("Database path: " + Path.GetDirectoryName(Path.GetFullPath(DbImporter.GetDbPath("fake.db", Environment.SpecialFolder.ApplicationData)))); if (Assembly.GetEntryAssembly().GetCustomAttribute <UserSecretsIdAttribute>() != null) { Console.WriteLine("Bot config path: " + Path.GetDirectoryName(Path.GetFullPath(Config.GoogleApiConfigPath))); } return; } if (Process.GetCurrentProcess().Id == 0) { Config.Log.Info("Well, this was unexpected"); } var singleInstanceCheckThread = new Thread(() => { using var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot"); if (instanceLock.WaitOne(1000)) { try { InstanceCheck.Release(); ShutdownCheck.Wait(); } finally { instanceLock.ReleaseMutex(); } } }); try { singleInstanceCheckThread.Start(); if (!await InstanceCheck.WaitAsync(1000).ConfigureAwait(false)) { Config.Log.Fatal("Another instance is already running."); return; } if (string.IsNullOrEmpty(Config.Token) || Config.Token.Length < 16) { Config.Log.Fatal("No token was specified."); return; } if (SandboxDetector.Detect() == SandboxType.Docker) { Config.Log.Info("Checking for updates..."); try { var(updated, stdout) = await Sudo.Bot.UpdateAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(stdout) && updated) { Config.Log.Debug(stdout); } if (updated) { Sudo.Bot.Restart(InvalidChannelId, "Restarted due to new bot updates not present in this Docker image"); return; } } catch (Exception e) { Config.Log.Error(e, "Failed to check for updates"); } } using (var db = new BotDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } using (var db = new ThumbnailDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } await SqlConfiguration.RestoreAsync().ConfigureAwait(false); Config.Log.Debug("Restored configuration variables from persistent storage"); await StatsStorage.RestoreAsync().ConfigureAwait(false); Config.Log.Debug("Restored stats from persistent storage"); var backgroundTasks = Task.WhenAll( AmdDriverVersionProvider.RefreshAsync(), #if !DEBUG new PsnScraper().RunAsync(Config.Cts.Token), GameTdbScraper.RunAsync(Config.Cts.Token), #endif StatsStorage.BackgroundSaveAsync(), CompatList.ImportCompatListAsync() ); try { if (!Directory.Exists(Config.IrdCachePath)) { Directory.CreateDirectory(Config.IrdCachePath); } } catch (Exception e) { Config.Log.Warn(e, $"Failed to create new folder {Config.IrdCachePath}: {e.Message}"); } var config = new DiscordConfiguration { Token = Config.Token, TokenType = TokenType.Bot, MessageCacheSize = Config.MessageCacheSize, LoggerFactory = Config.LoggerFactory, }; using var client = new DiscordClient(config); var commands = client.UseCommandsNext(new CommandsNextConfiguration { StringPrefixes = new[] { Config.CommandPrefix, Config.AutoRemoveCommandPrefix }, Services = new ServiceCollection().BuildServiceProvider(), }); commands.RegisterConverter(new TextOnlyDiscordChannelConverter()); commands.RegisterCommands <Misc>(); commands.RegisterCommands <CompatList>(); commands.RegisterCommands <Sudo>(); commands.RegisterCommands <CommandsManagement>(); commands.RegisterCommands <ContentFilters>(); commands.RegisterCommands <Warnings>(); commands.RegisterCommands <Explain>(); commands.RegisterCommands <Psn>(); commands.RegisterCommands <Invites>(); commands.RegisterCommands <Moderation>(); commands.RegisterCommands <Ird>(); commands.RegisterCommands <BotMath>(); commands.RegisterCommands <Pr>(); commands.RegisterCommands <Events>(); commands.RegisterCommands <E3>(); commands.RegisterCommands <Cyberpunk2077>(); commands.RegisterCommands <Rpcs3Ama>(); commands.RegisterCommands <BotStats>(); commands.RegisterCommands <Syscall>(); commands.RegisterCommands <ForcedNicknames>(); commands.RegisterCommands <Minesweeper>(); if (!string.IsNullOrEmpty(Config.AzureComputerVisionKey)) { commands.RegisterCommands <Vision>(); } commands.CommandErrored += UnknownCommandHandler.OnError; client.UseInteractivity(new InteractivityConfiguration()); client.Ready += async(c, _) => { var admin = await c.GetUserAsync(Config.BotAdminId).ConfigureAwait(false); Config.Log.Info("Bot is ready to serve!"); Config.Log.Info(""); Config.Log.Info($"Bot user id : {c.CurrentUser.Id} ({c.CurrentUser.Username})"); Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({admin.Username ?? "???"}#{admin.Discriminator ?? "????"})"); Config.Log.Info(""); }; client.GuildAvailable += async(c, gaArgs) => { await BotStatusMonitor.RefreshAsync(c).ConfigureAwait(false); Watchdog.DisconnectTimestamps.Clear(); Watchdog.TimeSinceLastIncomingMessage.Restart(); if (gaArgs.Guild.Id != Config.BotGuildId) { #if DEBUG Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})"); #else Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving..."); await gaArgs.Guild.LeaveAsync().ConfigureAwait(false); #endif return; } Config.Log.Info($"Server {gaArgs.Guild.Name} is available now"); Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}..."); try { await Task.WhenAll( Starbucks.CheckBacklogAsync(c, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default), DiscordInviteFilter.CheckBacklogAsync(c, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default) ).ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e, "Error running backlog tasks"); } Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}."); }; client.GuildAvailable += (c, _) => UsernameValidationMonitor.MonitorAsync(c, true); client.GuildUnavailable += (_, guArgs) => { Config.Log.Warn($"{guArgs.Guild.Name} is unavailable"); return(Task.CompletedTask); }; #if !DEBUG /* * client.GuildDownloadCompleted += async gdcArgs => * { * foreach (var guild in gdcArgs.Guilds) * await ModProvider.SyncRolesAsync(guild.Value).ConfigureAwait(false); * }; */ #endif client.MessageReactionAdded += Starbucks.Handler; client.MessageReactionAdded += ContentFilterMonitor.OnReaction; client.MessageCreated += (_, __) => { Watchdog.TimeSinceLastIncomingMessage.Restart(); return(Task.CompletedTask); }; client.MessageCreated += ContentFilterMonitor.OnMessageCreated; // should be first client.MessageCreated += GlobalMessageCache.OnMessageCreated; var mediaScreenshotMonitor = new MediaScreenshotMonitor(client); if (!string.IsNullOrEmpty(Config.AzureComputerVisionKey)) { client.MessageCreated += mediaScreenshotMonitor.OnMessageCreated; } client.MessageCreated += ProductCodeLookup.OnMessageCreated; client.MessageCreated += LogParsingHandler.OnMessageCreated; client.MessageCreated += LogAsTextMonitor.OnMessageCreated; client.MessageCreated += DiscordInviteFilter.OnMessageCreated; client.MessageCreated += PostLogHelpHandler.OnMessageCreated; client.MessageCreated += BotReactionsHandler.OnMessageCreated; client.MessageCreated += GithubLinksHandler.OnMessageCreated; client.MessageCreated += NewBuildsMonitor.OnMessageCreated; client.MessageCreated += TableFlipMonitor.OnMessageCreated; client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated; client.MessageCreated += EmpathySimulationHandler.OnMessageCreated; client.MessageUpdated += GlobalMessageCache.OnMessageUpdated; client.MessageUpdated += ContentFilterMonitor.OnMessageUpdated; client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated; client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated; client.MessageDeleted += GlobalMessageCache.OnMessageDeleted; if (Config.DeletedMessagesLogChannelId > 0) { client.MessageDeleted += DeletedMessagesMonitor.OnMessageDeleted; } client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted; client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted; client.MessagesBulkDeleted += GlobalMessageCache.OnMessagesBulkDeleted; client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated; client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated; client.GuildMemberAdded += Greeter.OnMemberAdded; client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameValidationMonitor.OnMemberAdded; client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameValidationMonitor.OnMemberUpdated; Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow); try { await client.ConnectAsync().ConfigureAwait(false); } catch (Exception e) { Config.Log.Error(e, "Failed to connect to Discord: " + e.Message); throw; } ulong? channelId = null; string restartMsg = null; using (var db = new BotDb()) { var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel"); if (chState != null) { if (ulong.TryParse(chState.Value, out var ch)) { channelId = ch; } db.BotState.Remove(chState); } var msgState = db.BotState.FirstOrDefault(i => i.Key == "bot-restart-msg"); if (msgState != null) { restartMsg = msgState.Value; db.BotState.Remove(msgState); } db.SaveChanges(); } if (string.IsNullOrEmpty(restartMsg)) { restartMsg = null; } if (channelId.HasValue) { Config.Log.Info($"Found channelId {channelId}"); DiscordChannel channel; if (channelId == InvalidChannelId) { channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false); await channel.SendMessageAsync(restartMsg ?? "Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false); } else { channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false); await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false); } } else { Config.Log.Debug($"Args count: {args.Length}"); var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]"); Config.Log.Debug("Args: " + string.Join(" ", pArgs)); } Config.Log.Debug("Running RPCS3 update check thread"); backgroundTasks = Task.WhenAll( backgroundTasks, NewBuildsMonitor.MonitorAsync(client), Watchdog.Watch(client), InviteWhitelistProvider.CleanupAsync(client), UsernameValidationMonitor.MonitorAsync(client), Psn.Check.MonitorFwUpdates(client, Config.Cts.Token), Watchdog.SendMetrics(client), Watchdog.CheckGCStats(), mediaScreenshotMonitor.ProcessWorkQueue() ); while (!Config.Cts.IsCancellationRequested) { if (client.Ping > 1000) { Config.Log.Warn($"High ping detected: {client.Ping}"); } await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => { /* in case it was cancelled */ }, TaskScheduler.Default).ConfigureAwait(false); } await backgroundTasks.ConfigureAwait(false); } catch (Exception e) { if (!Config.inMemorySettings.ContainsKey("shutdown")) { Config.Log.Fatal(e, "Experienced catastrophic failure, attempting to restart..."); } } finally { Config.TelemetryClient?.Flush(); ShutdownCheck.Release(); if (singleInstanceCheckThread.IsAlive) { singleInstanceCheckThread.Join(100); } } if (!Config.inMemorySettings.ContainsKey("shutdown")) { Sudo.Bot.Restart(InvalidChannelId, null); } }
public static async Task <bool> CheckMessageForInvitesAsync(DiscordClient client, DiscordMessage message) { if (message.Channel.IsPrivate) { return(true); } if (message.Author.IsBotSafeCheck()) { return(true); } #if !DEBUG if (message.Author.IsWhitelisted(client, message.Channel.Guild)) { return(true); } #endif if (message.Reactions.Any(r => r.Emoji == Config.Reactions.Moderated && r.IsMe)) { return(true); } var(hasInvalidResults, attemptedWorkaround, invites) = await client.GetInvitesAsync(message.Content, message.Author).ConfigureAwait(false); if (!hasInvalidResults && invites.Count == 0) { return(true); } if (hasInvalidResults) { try { DeletedMessagesMonitor.RemovedByBotCache.Set(message.Id, true, DeletedMessagesMonitor.CacheRetainTime); await message.DeleteAsync("Not a white-listed discord invite link").ConfigureAwait(false); await client.ReportAsync("🛃 An unapproved discord invite", message, "In invalid or expired invite", null, ReportSeverity.Low).ConfigureAwait(false); await message.Channel.SendMessageAsync($"{message.Author.Mention} please refrain from posting invites that were not approved by a moderator, especially expired or invalid.").ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e); await client.ReportAsync("🛃 An unapproved discord invite", message, "In invalid or expired invite", null, ReportSeverity.Medium).ConfigureAwait(false); await message.ReactWithAsync(Config.Reactions.Moderated, $"{message.Author.Mention} please remove this expired or invalid invite, and refrain from posting it again until you have received an approval from a moderator.", true ).ConfigureAwait(false); } return(false); } foreach (var invite in invites) { if (!await InviteWhitelistProvider.IsWhitelistedAsync(invite).ConfigureAwait(false)) { if (!InviteCodeCache.TryGetValue(message.Author.Id, out HashSet <string> recentInvites)) { recentInvites = new HashSet <string>(); } var circumventionAttempt = !recentInvites.Add(invite.Code) && attemptedWorkaround; //do not flip, must add to cache always InviteCodeCache.Set(message.Author.Id, recentInvites, CacheDuration); var removed = false; try { DeletedMessagesMonitor.RemovedByBotCache.Set(message.Id, true, DeletedMessagesMonitor.CacheRetainTime); await message.DeleteAsync("Not a white-listed discord invite").ConfigureAwait(false); removed = true; } catch (Exception e) { Config.Log.Warn(e); } var codeResolveMsg = $"Invite {invite.Code} was resolved to the {invite.Guild?.Name} server"; var reportMsg = codeResolveMsg; string userMsg; if (circumventionAttempt) { reportMsg += "\nAlso tried to workaround filter despite being asked not to do so."; userMsg = $"{message.Author.Mention} you have been asked nicely to not post invites to this unapproved discord server before."; } else { userMsg = $"{message.Author.Mention} invites to other servers must be whitelisted first.\n"; if (removed) { userMsg += "Please refrain from posting it again until you have received an approval from a moderator."; } else { userMsg += "Please remove it and refrain from posting it again until you have received an approval from a moderator."; } } await client.ReportAsync("🛃 An unapproved discord invite", message, reportMsg, null, ReportSeverity.Low).ConfigureAwait(false); await message.Channel.SendMessageAsync(userMsg).ConfigureAwait(false); if (circumventionAttempt) { await Warnings.AddAsync(client, message, message.Author.Id, message.Author.Username, client.CurrentUser, "Attempted to circumvent discord invite filter", codeResolveMsg); } return(false); } } return(true); }
internal static async Task Main(string[] args) { var singleInstanceCheckThread = new Thread(() => { using (var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot")) { if (instanceLock.WaitOne(1000)) { try { InstanceCheck.Release(); ShutdownCheck.Wait(); } finally { instanceLock.ReleaseMutex(); } } } }); try { singleInstanceCheckThread.Start(); if (!await InstanceCheck.WaitAsync(1000).ConfigureAwait(false)) { Config.Log.Fatal("Another instance is already running."); return; } if (string.IsNullOrEmpty(Config.Token)) { Config.Log.Fatal("No token was specified."); return; } using (var db = new BotDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } using (var db = new ThumbnailDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } await StatsStorage.RestoreAsync().ConfigureAwait(false); Config.Log.Debug("Restored stats from persistent storage"); var backgroundTasks = Task.WhenAll( AmdDriverVersionProvider.RefreshAsync(), new PsnScraper().RunAsync(Config.Cts.Token), GameTdbScraper.RunAsync(Config.Cts.Token), new AppveyorClient.Client().GetBuildAsync(Guid.NewGuid().ToString(), Config.Cts.Token), StatsStorage.BackgroundSaveAsync() ); try { if (!Directory.Exists(Config.IrdCachePath)) { Directory.CreateDirectory(Config.IrdCachePath); } } catch (Exception e) { Config.Log.Warn(e, $"Failed to create new folder {Config.IrdCachePath}: {e.Message}"); } var config = new DiscordConfiguration { Token = Config.Token, TokenType = TokenType.Bot, }; using (var client = new DiscordClient(config)) { var commands = client.UseCommandsNext(new CommandsNextConfiguration { StringPrefixes = new[] { Config.CommandPrefix, Config.AutoRemoveCommandPrefix }, Services = new ServiceCollection().BuildServiceProvider(), }); commands.RegisterConverter(new TextOnlyDiscordChannelConverter()); commands.RegisterCommands <Misc>(); commands.RegisterCommands <CompatList>(); commands.RegisterCommands <Sudo>(); commands.RegisterCommands <CommandsManagement>(); commands.RegisterCommands <ContentFilters>(); commands.RegisterCommands <Warnings>(); commands.RegisterCommands <Explain>(); commands.RegisterCommands <Psn>(); commands.RegisterCommands <Invites>(); commands.RegisterCommands <Moderation>(); commands.RegisterCommands <Ird>(); commands.RegisterCommands <BotMath>(); commands.RegisterCommands <Pr>(); commands.RegisterCommands <Events>(); commands.RegisterCommands <E3>(); commands.RegisterCommands <Cyberpunk2077>(); commands.RegisterCommands <Rpcs3Ama>(); commands.RegisterCommands <BotStats>(); commands.RegisterCommands <Syscall>(); commands.CommandErrored += UnknownCommandHandler.OnError; var interactivityConfig = new InteractivityConfiguration { }; client.UseInteractivity(interactivityConfig); client.Ready += async r => { Config.Log.Info("Bot is ready to serve!"); Config.Log.Info(""); Config.Log.Info($"Bot user id : {r.Client.CurrentUser.Id} ({r.Client.CurrentUser.Username})"); Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({(await r.Client.GetUserAsync(Config.BotAdminId)).Username})"); Config.Log.Info(""); }; client.GuildAvailable += async gaArgs => { await BotStatusMonitor.RefreshAsync(gaArgs.Client).ConfigureAwait(false); Watchdog.DisconnectTimestamps.Clear(); if (gaArgs.Guild.Id != Config.BotGuildId) { #if DEBUG Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})"); #else Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving..."); await gaArgs.Guild.LeaveAsync().ConfigureAwait(false); #endif return; } Config.Log.Info($"Server {gaArgs.Guild.Name} is available now"); Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}..."); try { await Task.WhenAll( Starbucks.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default), DiscordInviteFilter.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default) ).ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e, "Error running backlog tasks"); } Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}."); }; client.GuildUnavailable += guArgs => { Config.Log.Warn($"{guArgs.Guild.Name} is unavailable"); return(Task.CompletedTask); }; client.MessageReactionAdded += Starbucks.Handler; client.MessageReactionAdded += AntipiracyMonitor.OnReaction; client.MessageCreated += AntipiracyMonitor.OnMessageCreated; // should be first client.MessageCreated += ProductCodeLookup.OnMessageCreated; client.MessageCreated += LogParsingHandler.OnMessageCreated; client.MessageCreated += LogAsTextMonitor.OnMessageCreated; client.MessageCreated += DiscordInviteFilter.OnMessageCreated; client.MessageCreated += PostLogHelpHandler.OnMessageCreated; client.MessageCreated += BotReactionsHandler.OnMessageCreated; client.MessageCreated += AppveyorLinksHandler.OnMessageCreated; client.MessageCreated += GithubLinksHandler.OnMessageCreated; client.MessageCreated += NewBuildsMonitor.OnMessageCreated; client.MessageCreated += TableFlipMonitor.OnMessageCreated; client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated; client.MessageCreated += EmpathySimulationHandler.OnMessageCreated; client.MessageUpdated += AntipiracyMonitor.OnMessageUpdated; client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated; client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated; client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted; client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted; client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated; client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated; client.GuildMemberAdded += Greeter.OnMemberAdded; client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded; client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated; client.DebugLogger.LogMessageReceived += (sender, eventArgs) => { Action <Exception, string> logLevel = Config.Log.Info; if (eventArgs.Level == LogLevel.Debug) { logLevel = Config.Log.Debug; } else if (eventArgs.Level == LogLevel.Info) { //logLevel = Config.Log.Info; if (eventArgs.Message?.Contains("Session resumed") ?? false) { Watchdog.DisconnectTimestamps.Clear(); } } else if (eventArgs.Level == LogLevel.Warning) { logLevel = Config.Log.Warn; if (eventArgs.Message?.Contains("Dispatch:PRESENCES_REPLACE") ?? false) { BotStatusMonitor.RefreshAsync(client).ConfigureAwait(false).GetAwaiter().GetResult(); } } else if (eventArgs.Level == LogLevel.Error) { logLevel = Config.Log.Error; } else if (eventArgs.Level == LogLevel.Critical) { logLevel = Config.Log.Fatal; if ((eventArgs.Message?.Contains("Socket connection terminated") ?? false) || (eventArgs.Message?.Contains("heartbeats were skipped. Issuing reconnect.") ?? false)) { Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow); } } logLevel(eventArgs.Exception, eventArgs.Message); }; Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow); await client.ConnectAsync().ConfigureAwait(false); if (args.Length > 1 && ulong.TryParse(args[1], out var channelId)) { Config.Log.Info($"Found channelId: {args[1]}"); DiscordChannel channel; if (channelId == InvalidChannelId) { channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false); await channel.SendMessageAsync("Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false); } else { channel = await client.GetChannelAsync(channelId).ConfigureAwait(false); await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false); } } Config.Log.Debug("Running RPCS3 update check thread"); backgroundTasks = Task.WhenAll( backgroundTasks, NewBuildsMonitor.MonitorAsync(client), Watchdog.Watch(client), InviteWhitelistProvider.CleanupAsync(client) ); while (!Config.Cts.IsCancellationRequested) { if (client.Ping > 1000) { Config.Log.Warn($"High ping detected: {client.Ping}"); } await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => { /* in case it was cancelled */ }, TaskScheduler.Default).ConfigureAwait(false); } } await backgroundTasks.ConfigureAwait(false); } catch (Exception e) { if (!Config.inMemorySettings.ContainsKey("shutdown")) { Config.Log.Fatal(e, "Experienced catastrophic failure, attempting to restart..."); } } finally { ShutdownCheck.Release(); if (singleInstanceCheckThread.IsAlive) { singleInstanceCheckThread.Join(100); } } if (!Config.inMemorySettings.ContainsKey("shutdown")) { Sudo.Bot.Restart(InvalidChannelId); } }
private static async Task CheckMessageForInvitesAsync(DiscordClient client, DiscordMessage message) { if (DefaultHandlerFilter.IsFluff(message)) { return; } if (message.Author.IsWhitelisted(client, message.Channel.Guild)) { return; } if (message.Reactions.Any(r => r.Emoji == Config.Reactions.Moderated && r.IsMe)) { return; } var(hasInvalidResults, invites) = await client.GetInvitesAsync(message.Content).ConfigureAwait(false); if (!hasInvalidResults && invites.Count == 0) { return; } if (hasInvalidResults) { try { await message.DeleteAsync("Not a white-listed discord invite link").ConfigureAwait(false); await client.ReportAsync("An unapproved discord invite", message, "In invalid or expired invite", null, ReportSeverity.Low).ConfigureAwait(false); await message.Channel.SendMessageAsync($"{message.Author.Mention} please refrain from posting invites that were not approved by a moderator, especially expired or invalid.").ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e); await client.ReportAsync("An unapproved discord invite", message, "In invalid or expired invite", null, ReportSeverity.Medium).ConfigureAwait(false); await message.ReactWithAsync( client, Config.Reactions.Moderated, $"{message.Author.Mention} please remove this expired or invalid invite, and refrain from posting it again until you have recieved an approval from a moderator.", true ).ConfigureAwait(false); } return; } foreach (var invite in invites) { if (!await InviteWhitelistProvider.IsWhitelistedAsync(invite).ConfigureAwait(false)) { try { await message.DeleteAsync("Not a white-listed discord invite link").ConfigureAwait(false); await client.ReportAsync("An unapproved discord invite", message, $"Invite {invite.Code} was resolved to the {invite.Guild.Name} server", null, ReportSeverity.Low).ConfigureAwait(false); await message.Channel.SendMessageAsync($"{message.Author.Mention} invites to the {invite.Guild.Name.Sanitize()} server are not whitelisted.\n" + $"Please refrain from posting it again until you have recieved an approval from a moderator.").ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e); await client.ReportAsync("An unapproved discord invite", message, $"Invite {invite.Code} was resolved to the {invite.Guild.Name} server", null, ReportSeverity.Medium).ConfigureAwait(false); await message.ReactWithAsync( client, Config.Reactions.Moderated, $"{message.Author.Mention} invites to the {invite.Guild.Name.Sanitize()} server are not whitelisted.\n" + $"Please remove it and refrain from posting it again until you have recieved an approval from a moderator.", true ).ConfigureAwait(false); } return; } } }