private async Task AnnounceUserNote(UserNote userNote, IUser actor, RestAction action)
        {
            using var scope = _serviceProvider.CreateScope();

            _logger.LogInformation($"Announcing usernote {userNote.GuildId}/{userNote.UserId} ({userNote.Id}).");

            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(userNote.GuildId);

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                _logger.LogInformation($"Sending internal webhook for usernote {userNote.GuildId}/{userNote.UserId} ({userNote.Id}) to {guildConfig.ModInternalNotificationWebhook}.");

                try
                {
                    IUser user = await _discordAPI.FetchUserInfo(userNote.UserId, CacheBehavior.Default);

                    EmbedBuilder embed = await userNote.CreateUserNoteEmbed(action, actor, user, scope.ServiceProvider);

                    await _discordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build());
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing usernote {userNote.GuildId}/{userNote.UserId} ({userNote.Id}) to {guildConfig.ModInternalNotificationWebhook}.");
                }
            }
        }
Example #2
0
        public async Task HandleMemberJoin(SocketGuildUser user)
        {
            using var scope = _serviceProvider.CreateScope();
            Database database = scope.ServiceProvider.GetRequiredService <Database>();

            GuildConfig guildConfig;

            try
            {
                guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(user.Guild.Id);
            }
            catch (ResourceNotFoundException)
            {
                _logger.LogInformation($"Cannot execute punishment in guild {user.Guild.Id} - guildconfig not found.");
                return;
            }

            if (guildConfig.MutedRoles.Length == 0)
            {
                return;
            }

            List <ModCase> modCases = await database.SelectAllModCasesWithActiveMuteForGuildAndUser(user.Guild.Id, user.Id);

            if (modCases.Count == 0)
            {
                return;
            }

            _logger.LogInformation($"Muted member {user.Id} rejoined guild {user.Guild.Id}");
            await ExecutePunishment(modCases[0]);
        }
Example #3
0
        public async Task UndoPunishment(ModCase modCase)
        {
            using var scope = _serviceProvider.CreateScope();
            Database database = scope.ServiceProvider.GetRequiredService <Database>();

            List <ModCase> parallelCases = await database.SelectAllModCasesThatHaveParallelPunishment(modCase);

            if (parallelCases.Count != 0)
            {
                _logger.LogInformation("Cannot undo punishment. There exists a parallel punishment for this case");
                return;
            }

            GuildConfig guildConfig;

            try
            {
                guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);
            }
            catch (ResourceNotFoundException)
            {
                _logger.LogError($"Cannot execute punishment in guild {modCase.GuildId} - guildconfig not found.");
                return;
            }

            string reason = null;

            try
            {
                Translator translator = scope.ServiceProvider.GetRequiredService <Translator>();
                reason = translator.T(guildConfig).NotificationDiscordAuditLogPunishmentsUndone(modCase.CaseId, modCase.Title.Truncate(400));
            } catch (Exception ex)
            {
                _logger.LogError(ex, $"Failed to resolve audit log reason string for case {modCase.GuildId}/{modCase.CaseId}");
            }
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                if (guildConfig.MutedRoles.Length != 0)
                {
                    _logger.LogInformation($"Unmute User {modCase.UserId} in guild {modCase.GuildId} with roles " + string.Join(',', guildConfig.MutedRoles.Select(x => x.ToString())));
                    foreach (ulong role in guildConfig.MutedRoles)
                    {
                        await _discord.RemoveGuildUserRole(modCase.GuildId, modCase.UserId, role, reason);
                    }
                }
                else
                {
                    _logger.LogInformation($"Cannot Unmute User {modCase.UserId} in guild {modCase.GuildId} - mute role undefined.");
                }
                break;

            case PunishmentType.Ban:
                _logger.LogInformation($"Unban User {modCase.UserId} in guild {modCase.GuildId}.");
                await _discord.UnBanUser(modCase.GuildId, modCase.UserId, reason);

                _discord.RemoveFromCache(CacheKey.GuildBan(modCase.GuildId, modCase.UserId));      // refresh ban cache
                break;
            }
        }
        public async Task <IActionResult> Status()
        {
            Identity currentIdentity = await GetIdentity();

            if (!currentIdentity.IsSiteAdmin())
            {
                return(Unauthorized());
            }

            List <string> currentLogins = new();

            foreach (var login in _identityManager.GetCurrentIdentities())
            {
                if (login is DiscordOAuthIdentity)
                {
                    try
                    {
                        var user = login.GetCurrentUser();
                        if (user == null)
                        {
                            currentLogins.Add($"Invalid user.");
                        }
                        else
                        {
                            currentLogins.Add($"{user.Username}#{user.Discriminator}");
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e, "Error getting logged in user.");
                        currentLogins.Add($"Invalid user.");
                    }
                }
            }

            StatusRepository repo = StatusRepository.CreateDefault(_serviceProvider);

            StatusDetail botDetails = repo.GetBotStatus();
            StatusDetail dbDetails  = await repo.GetDbStatus();

            StatusDetail cacheDetails = repo.GetCacheStatus();

            return(Ok(new
            {
                botStatus = botDetails,
                dbStatus = dbDetails,
                cacheStatus = cacheDetails,
                loginsInLast15Minutes = currentLogins,
                defaultLanguage = _config.GetDefaultLanguage(),
                trackedInvites = await InviteRepository.CreateDefault(_serviceProvider).CountInvites(),
                modCases = await ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity).CountAllCases(),
                guilds = await GuildConfigRepository.CreateDefault(_serviceProvider).CountGuildConfigs(),
                automodEvents = await AutoModerationEventRepository.CreateDefault(_serviceProvider).CountEvents(),
                userNotes = await UserNoteRepository.CreateWithBotIdentity(_serviceProvider).CountUserNotes(),
                userMappings = await UserMapRepository.CreateWithBotIdentity(_serviceProvider).CountAllUserMaps(),
                apiTokens = await TokenRepository.CreateDefault(_serviceProvider).CountTokens(),
                nextCache = _scheduler.GetNextCacheSchedule(),
                cachedDataFromDiscord = _discordAPI.GetCache().Keys
            }));
        }
Example #5
0
        public async Task ExecutePunishment(ModCase modCase)
        {
            using var scope = _serviceProvider.CreateScope();
            Database database = scope.ServiceProvider.GetRequiredService <Database>();

            GuildConfig guildConfig;

            try
            {
                guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);
            }
            catch (ResourceNotFoundException)
            {
                _logger.LogError($"Cannot execute punishment in guild {modCase.GuildId} - guildconfig not found.");
                return;
            }

            string reason = null;

            try
            {
                Translator translator = scope.ServiceProvider.GetRequiredService <Translator>();
                reason = translator.T(guildConfig).NotificationDiscordAuditLogPunishmentsExecute(modCase.CaseId, modCase.LastEditedByModId, modCase.Title.Truncate(400));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Failed to resolve audit log reason string for case {modCase.GuildId}/{modCase.CaseId}");
            }
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                if (guildConfig.MutedRoles.Length != 0)
                {
                    _logger.LogInformation($"Mute User {modCase.UserId} in guild {modCase.GuildId} with roles " + string.Join(',', guildConfig.MutedRoles.Select(x => x.ToString())));
                    foreach (ulong role in guildConfig.MutedRoles)
                    {
                        await _discord.GrantGuildUserRole(modCase.GuildId, modCase.UserId, role, reason);
                    }
                }
                else
                {
                    _logger.LogInformation($"Cannot Mute User {modCase.UserId} in guild {modCase.GuildId} - mute role undefined.");
                }
                break;

            case PunishmentType.Ban:
                _logger.LogInformation($"Ban User {modCase.UserId} in guild {modCase.GuildId}.");
                await _discord.BanUser(modCase.GuildId, modCase.UserId, reason);

                await _discord.GetGuildUserBan(modCase.GuildId, modCase.UserId, CacheBehavior.IgnoreCache);      // refresh ban cache

                break;

            case PunishmentType.Kick:
                _logger.LogInformation($"Kick User {modCase.UserId} in guild {modCase.GuildId}.");
                await _discord.KickGuildUser(modCase.GuildId, modCase.UserId, reason);

                break;
            }
        }
        public async Task <IActionResult> UpdateSpecificItem([FromRoute] ulong guildId, [FromBody] GuildConfigForPutDto newValue)
        {
            await RequirePermission(guildId, DiscordPermission.Admin);

            if (_config.IsDemoModeEnabled())
            {
                if (!(await GetIdentity()).IsSiteAdmin())
                {  // siteadmins can overwrite in demo mode
                    throw new BaseAPIException("Demo mode is enabled. Only site admins can edit guild configs.", APIError.NotAllowedInDemoMode);
                }
            }

            GuildConfig guildConfig = await GetRegisteredGuild(guildId);

            guildConfig.ModRoles          = newValue.ModRoles;
            guildConfig.AdminRoles        = newValue.AdminRoles;
            guildConfig.ModNotificationDM = newValue.ModNotificationDM;
            guildConfig.MutedRoles        = newValue.MutedRoles;
            guildConfig.ModInternalNotificationWebhook = newValue.ModInternalNotificationWebhook;
            if (guildConfig.ModInternalNotificationWebhook != null)
            {
                guildConfig.ModInternalNotificationWebhook = guildConfig.ModInternalNotificationWebhook.Replace("discord.com", "discordapp.com");
            }
            guildConfig.ModPublicNotificationWebhook = newValue.ModPublicNotificationWebhook;
            if (guildConfig.ModPublicNotificationWebhook != null)
            {
                guildConfig.ModPublicNotificationWebhook = guildConfig.ModPublicNotificationWebhook.Replace("discord.com", "discordapp.com");
            }
            guildConfig.StrictModPermissionCheck = newValue.StrictModPermissionCheck;
            guildConfig.ExecuteWhoisOnJoin       = newValue.ExecuteWhoisOnJoin;
            guildConfig.PublishModeratorInfo     = newValue.PublishModeratorInfo;
            guildConfig.PreferredLanguage        = newValue.PreferredLanguage;

            return(Ok(await GuildConfigRepository.CreateDefault(_serviceProvider).UpdateGuildConfig(guildConfig)));
        }
        public async Task <IActionResult> CreateItem([FromBody] GuildConfigForCreateDto guildConfigForCreateDto, [FromQuery] bool importExistingBans = false)
        {
            await RequireSiteAdmin();

            try
            {
                GuildConfig alreadyRegistered = await GetRegisteredGuild(guildConfigForCreateDto.GuildId);

                if (alreadyRegistered != null)
                {
                    throw new GuildAlreadyRegisteredException(guildConfigForCreateDto.GuildId);
                }
            }
            catch (ResourceNotFoundException) { }
            catch (UnregisteredGuildException) { }

            GuildConfig guildConfig = new()
            {
                GuildId                        = guildConfigForCreateDto.GuildId,
                ModRoles                       = guildConfigForCreateDto.ModRoles,
                AdminRoles                     = guildConfigForCreateDto.AdminRoles,
                ModNotificationDM              = guildConfigForCreateDto.ModNotificationDM,
                MutedRoles                     = guildConfigForCreateDto.MutedRoles,
                ModPublicNotificationWebhook   = guildConfigForCreateDto.ModPublicNotificationWebhook,
                ModInternalNotificationWebhook = guildConfigForCreateDto.ModInternalNotificationWebhook,
                StrictModPermissionCheck       = guildConfigForCreateDto.StrictModPermissionCheck,
                ExecuteWhoisOnJoin             = guildConfigForCreateDto.ExecuteWhoisOnJoin,
                PublishModeratorInfo           = guildConfigForCreateDto.PublishModeratorInfo,
                PreferredLanguage              = guildConfigForCreateDto?.PreferredLanguage ?? _config.GetDefaultLanguage()
            };

            guildConfig = await GuildConfigRepository.CreateDefault(_serviceProvider).CreateGuildConfig(guildConfig, importExistingBans);

            return(StatusCode(201, guildConfig));
        }
Example #8
0
        public async Task SetContext(ulong guildId)
        {
            using var scope = _serviceProvider.CreateScope();
            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(guildId);

            SetContext(guildConfig);
        }
        private async Task AnnounceAutomoderationConfig(AutoModerationConfig config, IUser actor, RestAction action)
        {
            using var scope = _serviceProvider.CreateScope();

            _logger.LogInformation($"Announcing automod config {config.GuildId}/{config.AutoModerationType} ({config.Id}).");


            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(config.GuildId);

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                _logger.LogInformation($"Sending internal webhook for config {config.GuildId}/{config.AutoModerationType} ({config.Id}) to {guildConfig.ModInternalNotificationWebhook}.");

                try
                {
                    EmbedBuilder embed = await config.CreateAutomodConfigEmbed(actor, action, _serviceProvider);

                    await _discordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build());
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing config  {config.GuildId}/{config.AutoModerationType} ({config.Id}) to {guildConfig.ModInternalNotificationWebhook}.");
                }
            }
        }
Example #10
0
        public static async Task <AutoModerator> CreateDefault(IDiscordClient client, ulong guildId, IServiceProvider serviceProvider)
        {
            var guildConfig = await GuildConfigRepository.CreateDefault(serviceProvider).GetGuildConfig(guildId);

            var autoModerationConfigs = await AutoModerationConfigRepository.CreateWithBotIdentity(serviceProvider).GetConfigsByGuild(guildId);

            return(new AutoModerator(client, serviceProvider, guildConfig, autoModerationConfigs));
        }
        public async Task <IActionResult> DeleteSpecificItem([FromRoute] ulong guildId, [FromQuery] bool deleteData = false)
        {
            await RequireSiteAdmin();
            await GetRegisteredGuild(guildId);

            await GuildConfigRepository.CreateDefault(_serviceProvider).DeleteGuildConfig(guildId, deleteData);

            return(Ok());
        }
Example #12
0
        public async Task <IActionResult> GetUser()
        {
            Identity identity = await GetIdentity();

            IUser            currentUser       = identity.GetCurrentUser();
            List <UserGuild> currentUserGuilds = identity.GetCurrentUserGuilds();

            List <DiscordGuildView> memberGuilds = new();
            List <DiscordGuildView> modGuilds    = new();
            List <DiscordGuildView> adminGuilds  = new();
            List <DiscordGuildView> bannedGuilds = new();
            bool siteAdmin = _config.GetSiteAdmins().Contains(currentUser.Id) || identity is TokenIdentity;

            if (identity is DiscordOAuthIdentity)
            {
                List <GuildConfig> registeredGuilds = await GuildConfigRepository.CreateDefault(_serviceProvider).GetAllGuildConfigs();

                foreach (GuildConfig guild in registeredGuilds)
                {
                    UserGuild userGuild = currentUserGuilds.FirstOrDefault(x => x.Id == guild.GuildId);
                    if (userGuild != null)
                    {
                        IGuild userGuildFetched = _discordAPI.FetchGuildInfo(userGuild.Id, CacheBehavior.Default);
                        if (userGuildFetched != null)
                        {
                            if (await identity.HasModRoleOrHigherOnGuild(guild.GuildId))
                            {
                                if (await identity.HasAdminRoleOnGuild(guild.GuildId))
                                {
                                    adminGuilds.Add(new DiscordGuildView(userGuildFetched));
                                }
                                else
                                {
                                    modGuilds.Add(new DiscordGuildView(userGuildFetched));
                                }
                            }
                            else
                            {
                                memberGuilds.Add(new DiscordGuildView(userGuildFetched));
                            }
                        }
                    }
                    else
                    {
                        try
                        {
                            _discordAPI.GetFromCache <IBan>(CacheKey.GuildBan(guild.GuildId, currentUser.Id));
                            bannedGuilds.Add(new DiscordGuildView(_discordAPI.FetchGuildInfo(guild.GuildId, CacheBehavior.Default)));
                        }
                        catch (NotFoundInCacheException) { }
                    }
                }
            }

            return(Ok(new APIUser(memberGuilds, bannedGuilds, modGuilds, adminGuilds, currentUser, siteAdmin)));
        }
Example #13
0
        public async Task Say([Summary("message", "message content the bot shall write")] string message, [Summary("channel", "channel to write the message in, defaults to current")] ITextChannel channel = null)
        {
            if (channel is null && Context.Channel is not ITextChannel)
            {
                await Context.Interaction.RespondAsync(Translator.T().CmdOnlyTextChannel(), ephemeral : true);

                return;
            }

            if (channel is null)
            {
                channel = Context.Channel as ITextChannel;
            }

            try
            {
                IUserMessage createdMessage = await channel.SendMessageAsync(message);

                await Context.Interaction.RespondAsync(Translator.T().CmdSaySent(), ephemeral : true);

                try
                {
                    GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(ServiceProvider).GetGuildConfig(Context.Guild.Id);

                    if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
                    {
                        await DiscordAPI.ExecuteWebhook(
                            guildConfig.ModInternalNotificationWebhook,
                            null,
                            Translator.T().CmdSaySentMod(
                                Context.User,
                                createdMessage,
                                channel
                                ),
                            AllowedMentions.None
                            );
                    }
                } catch (Exception ex)
                {
                    Logger.LogError(ex, $"Something went wrong while sending the internal notification for the say command by {Context.User.Id} in {Context.Guild.Id}/{Context.Channel.Id}.");
                }
            }
            catch (HttpException e)
            {
                if (e.HttpCode == HttpStatusCode.Unauthorized)
                {
                    await Context.Interaction.RespondAsync(Translator.T().CmdCannotViewOrDeleteInChannel(), ephemeral : true);
                }
            }
            catch (Exception e)
            {
                Logger.LogError(e, $"Error while writing message in channel {channel.Id}");
                await Context.Interaction.RespondAsync(Translator.T().CmdSayFailed(), ephemeral : true);
            }
        }
 protected async Task <GuildConfig> GetRegisteredGuild(ulong guildId)
 {
     try
     {
         return(await GuildConfigRepository.CreateDefault(_serviceProvider).GetGuildConfig(guildId));
     }
     catch (ResourceNotFoundException)
     {
         throw new UnregisteredGuildException(guildId);
     }
 }
Example #15
0
        public async Task Report(IMessage msg)
        {
            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(ServiceProvider).GetGuildConfig(Context.Guild.Id);

            if (string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                await Context.Interaction.RespondAsync(Translator.T().CmdNoWebhookConfigured(), ephemeral : true);

                return;
            }

            StringBuilder sb = new();

            sb.AppendLine(Translator.T().CmdReportContent(Context.User, msg, msg.Channel as ITextChannel));

            if (!string.IsNullOrEmpty(msg.Content))
            {
                sb.Append("```\n");
                sb.Append(msg.Content.Truncate(1024));
                sb.Append("\n``` ");
            }

            if (msg.Attachments.Count > 0)
            {
                sb.AppendLine(Translator.T().Attachments());
                foreach (IAttachment attachment in msg.Attachments.Take(5))
                {
                    sb.Append($"- <{attachment.Url}>\n");
                }
                if (msg.Attachments.Count > 5)
                {
                    sb.AppendLine(Translator.T().AndXMore(msg.Attachments.Count - 5));
                }
            }

            try
            {
                await DiscordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, null, sb.ToString(), AllowedMentions.None);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Failed to send internal notification to moderators for report command.");
                await Context.Interaction.RespondAsync(Translator.T().CmdReportFailed(), ephemeral : true);

                return;
            }

            await Context.Interaction.RespondAsync(Translator.T().CmdReportSent(), ephemeral : true);
        }
 private static async Task RequireRegisteredGuild(IServiceProvider services, IInteractionContext context)
 {
     try
     {
         await GuildConfigRepository.CreateDefault(services).GetGuildConfig(context.Guild.Id);
     }
     catch (ResourceNotFoundException)
     {
         throw new UnregisteredGuildException(context.Guild.Id);
     }
     catch (NullReferenceException)
     {
         throw new BaseAPIException("Only usable in a guild.", APIError.OnlyUsableInAGuild);
     }
 }
Example #17
0
 public WARBOT()
 {
     Config = BotConfig.Load();
     Client = new DiscordSocketClient(new DiscordSocketConfig
     {
         AlwaysDownloadUsers = false,
     });
     commands = new CommandService(new CommandServiceConfig
     {
         DefaultRunMode        = RunMode.Async,
         CaseSensitiveCommands = false,
         IgnoreExtraArgs       = true,
     });
     Log       = new Util.Log(this);
     GuildRepo = new GuildConfigRepository();
     TaskBot   = new TaskBOT.TaskBOT(this);
 }
Example #18
0
        public PrefixCommandHandler(IServiceProvider provider, DiscordSocketClient client,
                                    CommandServiceConfig commandServiceConfig, CommandHandlerOptions options,
                                    CustomModuleBuilder moduleBuilder,
                                    IEnumerable <IPluginFactory> pluginFactories,
                                    ILogger <PrefixCommandHandler> logger, CommandService commandService, GuildConfigRepository guildConfigRepository, RepeatRepository repeatRepository)
            : base(provider, client, commandServiceConfig, moduleBuilder, pluginFactories, logger, commandService)
        {
            this.Options = options;
            this.logger  = logger;

            this.CommandTriggered += this.CommandTriggeredAsync;
            this.CommandMissing   += this.CommandMissingAsync;
            this.CommandSucceeded += this.CommandSucceededAsync;
            this.CommandFailed    += this.CommandFailedAsync;
            this.CommandExecuted  += this.CommandExecutedAsync;

            this._guildConfigRepository = guildConfigRepository;
            this._repeatRepository      = repeatRepository;
        }
Example #19
0
        public async Task SendEmbed(EmbedBuilder embed, ulong guildID, GuildAuditLogEvent eventType)
        {
            var guildConfigRepository = GuildConfigRepository.CreateDefault(_serviceProvider);

            embed
            .WithColor(eventType switch
            {
                GuildAuditLogEvent.MessageSent => Color.Green,
                GuildAuditLogEvent.MessageUpdated => Color.Orange,
                GuildAuditLogEvent.MessageDeleted => Color.Red,
                GuildAuditLogEvent.UsernameUpdated => Color.Orange,
                GuildAuditLogEvent.AvatarUpdated => Color.Orange,
                GuildAuditLogEvent.NicknameUpdated => Color.Orange,
                GuildAuditLogEvent.MemberRolesUpdated => Color.Orange,
                GuildAuditLogEvent.MemberJoined => Color.Green,
                GuildAuditLogEvent.MemberRemoved => Color.Red,
                GuildAuditLogEvent.BanAdded => Color.Red,
                GuildAuditLogEvent.BanRemoved => Color.Green,
                GuildAuditLogEvent.InviteCreated => Color.Green,
                GuildAuditLogEvent.InviteDeleted => Color.Red,
                GuildAuditLogEvent.ThreadCreated => Color.Green,
                _ => throw new NotImplementedException(),
            })
        private async Task AnnounceFile(UploadedFile file, ModCase modCase, IUser actor, RestAction action)
        {
            using var scope = _serviceProvider.CreateScope();

            _logger.LogInformation($"Announcing file {modCase.GuildId}/{modCase.CaseId}/{file.Name}.");

            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                _logger.LogInformation($"Sending internal webhook for file {modCase.GuildId}/{modCase.CaseId}/{file.Name} to {guildConfig.ModInternalNotificationWebhook}.");
                try
                {
                    EmbedBuilder embed = await file.CreateFileEmbed(modCase, action, actor, scope.ServiceProvider);

                    await _discordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build());
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing file {modCase.GuildId}/{modCase.CaseId}/{file.Name} to {guildConfig.ModInternalNotificationWebhook}.");
                }
            }
        }
Example #21
0
        private async Task GuildMemberAddedHandler(SocketGuildUser member)
        {
            using var scope = _serviceProvider.CreateScope();

            var translator = scope.ServiceProvider.GetRequiredService <Translator>();
            await translator.SetContext(member.Guild.Id);

            // Refresh identity memberships
            IdentityManager identityManager = scope.ServiceProvider.GetRequiredService <IdentityManager>();

            foreach (Identity identity in identityManager.GetCurrentIdentities())
            {
                if (identity.GetCurrentUser().Id == member.Id)
                {
                    identity.AddGuildMembership(member);
                }
            }

            // Refresh member cache
            DiscordAPIInterface discordAPI = scope.ServiceProvider.GetRequiredService <DiscordAPIInterface>();

            discordAPI.AddOrUpdateCache(CacheKey.GuildMember(member.Guild.Id, member.Id), new CacheApiResponse(member));

            GuildConfig guildConfig;

            try
            {
                guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(member.Guild.Id);
            }
            catch (ResourceNotFoundException)
            {
                return;
            }

            try
            {
                Punishments handler = scope.ServiceProvider.GetRequiredService <Punishments>();
                await handler.HandleMemberJoin(member);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to handle punishment on member join.");
            }

            if (member.IsBot)
            {
                return;
            }

            List <TrackedInvite> newInvites = await FetchInvites(member.Guild);

            TrackedInvite usedInvite = null;

            try
            {
                usedInvite = InviteTracker.GetUsedInvite(member.Guild.Id, newInvites);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get used invite.");
            }

            InviteTracker.AddInvites(member.Guild.Id, newInvites);

            if (usedInvite != null)
            {
                UserInvite invite = new()
                {
                    GuildId         = member.Guild.Id,
                    JoinedUserId    = member.Id,
                    JoinedAt        = DateTime.UtcNow,
                    InviteIssuerId  = usedInvite.CreatorId,
                    InviteCreatedAt = usedInvite.CreatedAt,
                    TargetChannelId = usedInvite.TargetChannelId,
                    UsedInvite      = $"https://discord.gg/{usedInvite.Code}"
                };

                _logger.LogInformation($"User {member.Username}#{member.Discriminator} joined guild {member.Guild.Name} with ID: {member.Guild.Id} using invite {usedInvite.Code}");

                if (guildConfig.ExecuteWhoisOnJoin && !string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
                {
                    string message;

                    if (invite.InviteIssuerId != 0 && invite.InviteCreatedAt != null)
                    {
                        message = translator.T().NotificationAutoWhoisJoinWithAndFrom(member, invite.InviteIssuerId, invite.InviteCreatedAt.Value, member.CreatedAt.DateTime, invite.UsedInvite);
                    }
                    else
                    {
                        message = translator.T().NotificationAutoWhoisJoinWith(member, member.CreatedAt.DateTime, invite.UsedInvite);
                    }

                    await discordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, null, message, AllowedMentions.None);
                }

                await InviteRepository.CreateDefault(scope.ServiceProvider).CreateInvite(invite);
            }
        }
Example #22
0
        public async Task <bool> IsAllowedTo(APIActionPermission permission, ModCase modCase)
        {
            if (modCase == null)
            {
                return(false);
            }
            if (IsSiteAdmin())
            {
                return(true);
            }
            switch (permission)
            {
            case APIActionPermission.View:
                if (currentUser == null)
                {
                    return(false);
                }
                return(modCase.UserId == currentUser.Id || await HasPermissionOnGuild(DiscordPermission.Moderator, modCase.GuildId));

            case APIActionPermission.Delete:
                return(await HasPermissionOnGuild(DiscordPermission.Moderator, modCase.GuildId));

            case APIActionPermission.ForceDelete:
                return(false);     // only siteadmin

            case APIActionPermission.Edit:
                GuildConfig guildConfig;
                try
                {
                    using var scope = _serviceProvider.CreateScope();
                    guildConfig     = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);
                }
                catch (ResourceNotFoundException)
                {
                    return(false);
                }
                if (guildConfig.StrictModPermissionCheck && modCase.PunishmentType != PunishmentType.Warn)
                {
                    GuildPermission x = GuildPermission.CreateInstantInvite;
                    if (modCase.PunishmentType == PunishmentType.Kick)
                    {
                        x = GuildPermission.KickMembers;
                    }
                    if (modCase.PunishmentType == PunishmentType.Ban)
                    {
                        x = GuildPermission.BanMembers;
                    }
                    if (modCase.PunishmentType == PunishmentType.Mute)
                    {
                        x = GuildPermission.ManageRoles;
                    }
                    if (await HasPermissionOnGuild(DiscordPermission.Admin, modCase.GuildId))
                    {
                        return(true);
                    }
                    return(await HasPermissionOnGuild(DiscordPermission.Moderator, modCase.GuildId) &&
                           await HasRolePermissionInGuild(modCase.GuildId, x));
                }
                return(await HasPermissionOnGuild(DiscordPermission.Moderator, modCase.GuildId));
            }
            return(false);
        }
        public async Task <IActionResult> GetSpecificItem([FromRoute] ulong guildId)
        {
            await RequirePermission(guildId, DiscordPermission.Admin);

            return(Ok(new GuildConfigView(await GuildConfigRepository.CreateDefault(_serviceProvider).GetGuildConfig(guildId))));
        }
Example #24
0
        public async Task Features()
        {
            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(ServiceProvider).GetGuildConfig(Context.Guild.Id);

            GuildFeatureTest featureTest = new(guildConfig, Context.Guild.CurrentUser);

            EmbedBuilder embed = new();

            embed.WithTimestamp(DateTime.UtcNow);

            StringBuilder missingBasicPermissions = new();

            // kick
            if (featureTest.HasKickPermission())
            {
                missingBasicPermissions.Append($"\n- {CHECK} {Translator.T().CmdFeaturesKickPermissionGranted()}");
            }
            else
            {
                missingBasicPermissions.Append($"\n- {X_CHECK} {Translator.T().CmdFeaturesKickPermissionNotGranted()}");
            }

            // ban
            if (featureTest.HasBanPermission())
            {
                missingBasicPermissions.Append($"\n- {CHECK} {Translator.T().CmdFeaturesBanPermissionGranted()}");
            }
            else
            {
                missingBasicPermissions.Append($"\n- {X_CHECK} {Translator.T().CmdFeaturesBanPermissionNotGranted()}");
            }

            // mute
            if (featureTest.HasManagedRolePermission())
            {
                missingBasicPermissions.Append($"\n- {CHECK} {Translator.T().CmdFeaturesManageRolePermissionGranted()}");
            }
            else
            {
                missingBasicPermissions.Append($"\n- {X_CHECK} {Translator.T().CmdFeaturesManageRolePermissionNotGranted()}");
            }

            // muted role
            if (!featureTest.HasMutedRolesDefined())
            {
                missingBasicPermissions.Append($"\n- {X_CHECK} {Translator.T().CmdFeaturesMutedRoleUndefined()}");
            }
            else
            {
                switch (featureTest.HasManagableMutedRoles())
                {
                case GuildFeatureTestResult.Ok:
                    missingBasicPermissions.Append($"\n- {CHECK} {Translator.T().CmdFeaturesMutedRoleDefined()}");
                    break;

                case GuildFeatureTestResult.RoleTooHigh:
                    missingBasicPermissions.Append($"\n- {X_CHECK} {Translator.T().CmdFeaturesMutedRoleDefinedButTooHigh()}");
                    break;

                default:
                    missingBasicPermissions.Append($"\n- {X_CHECK} {Translator.T().CmdFeaturesMutedRoleDefinedButInvalid()}");
                    break;
                }
            }


            // basic punishment feature
            if (featureTest.FeaturePunishmentExecution())
            {
                embed.AddField($"{CHECK} {Translator.T().CmdFeaturesPunishmentExecution()}", Translator.T().CmdFeaturesPunishmentExecutionDescription(), false);
            }
            else
            {
                embed.AddField($"{X_CHECK} {Translator.T().CmdFeaturesPunishmentExecution()}", Translator.T().CmdFeaturesPunishmentExecutionDescription() + missingBasicPermissions.ToString(), false);
            }

            // unban feature
            if (featureTest.HasBanPermission())
            {
                embed.AddField($"{CHECK} {Translator.T().CmdFeaturesUnbanRequests()}", Translator.T().CmdFeaturesUnbanRequestsDescriptionGranted(), false);
            }
            else
            {
                embed.AddField($"{X_CHECK} {Translator.T().CmdFeaturesUnbanRequests()}", Translator.T().CmdFeaturesUnbanRequestsDescriptionNotGranted(), false);
            }

            // report command
            if (featureTest.HasInternalWebhookDefined())
            {
                embed.AddField($"{CHECK} {Translator.T().CmdFeaturesReportCommand()}", Translator.T().CmdFeaturesReportCommandDescriptionGranted(), false);
            }
            else
            {
                embed.AddField($"{X_CHECK} {Translator.T().CmdFeaturesReportCommand()}", Translator.T().CmdFeaturesReportCommandDescriptionNotGranted(), false);
            }

            // invite tracking
            if (featureTest.HasManagedGuildPermission())
            {
                embed.AddField($"{CHECK} {Translator.T().CmdFeaturesInviteTracking()}", Translator.T().CmdFeaturesInviteTrackingDescriptionGranted(), false);
            }
            else
            {
                embed.AddField($"{X_CHECK} {Translator.T().CmdFeaturesInviteTracking()}", Translator.T().CmdFeaturesInviteTrackingDescriptionNotGranted(), false);
            }

            if (featureTest.SupportsAllFeatures())
            {
                embed.WithTitle(Translator.T().CmdFeaturesSupportAllFeatures())
                .WithDescription(Translator.T().CmdFeaturesSupportAllFeaturesDesc())
                .WithColor(Color.Green);
            }
            else
            {
                embed.WithTitle(Translator.T().CmdFeaturesMissingFeatures())
                .WithColor(Color.Red);
            }

            await Context.Interaction.RespondAsync(embed : embed.Build());
        }
Example #25
0
 public NewGuildWatcher(GuildConfigRepository repository, DiscordSocketClient discordClient)
 {
     this._repository    = repository;
     this._discordClient = discordClient;
 }
        public override async Task <PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services)
        {
            var identity = await services.GetRequiredService <IdentityManager>().GetIdentity(context.User);

            foreach (RequireCheckEnum check in _checks)
            {
                switch (check)
                {
                case RequireCheckEnum.GuildRegistered:
                    await RequireRegisteredGuild(services, context);

                    continue;

                case RequireCheckEnum.GuildMember:
                    await RequireDiscordPermission(DiscordPermission.Member, services, context, identity);

                    continue;

                case RequireCheckEnum.GuildModerator:
                    await RequireDiscordPermission(DiscordPermission.Moderator, services, context, identity);

                    continue;

                case RequireCheckEnum.GuildAdmin:
                    await RequireDiscordPermission(DiscordPermission.Admin, services, context, identity);

                    continue;

                case RequireCheckEnum.GuildMuteRole:
                    try
                    {
                        GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(services).GetGuildConfig(context.Guild.Id);

                        if (guildConfig.MutedRoles.Length == 0)
                        {
                            throw new GuildWithoutMutedRoleException(context.Guild.Id);
                        }
                    }
                    catch (ResourceNotFoundException)
                    {
                        throw new UnregisteredGuildException(context.Guild.Id);
                    }
                    continue;

                case RequireCheckEnum.SiteAdmin:
                    if (!identity.IsSiteAdmin())
                    {
                        throw new UnauthorizedException("Only site admins allowed.");
                    }
                    continue;

                case RequireCheckEnum.GuildStrictModeMute:
                    await RequireStrictModeAccess(PunishmentType.Mute, services, context, identity);

                    continue;

                case RequireCheckEnum.GuildStrictModeKick:
                    await RequireStrictModeAccess(PunishmentType.Kick, services, context, identity);

                    continue;

                case RequireCheckEnum.GuildStrictModeBan:
                    await RequireStrictModeAccess(PunishmentType.Ban, services, context, identity);

                    continue;
                }
            }
            return(PreconditionResult.FromSuccess());
        }
Example #27
0
        public async Task <IActionResult> GetUserNetwork([FromQuery][Required] ulong userId)
        {
            Identity currentIdentity = await GetIdentity();

            List <string>           modGuilds  = new();
            List <DiscordGuildView> guildViews = new();

            List <GuildConfig> guildConfigs = await GuildConfigRepository.CreateDefault(_serviceProvider).GetAllGuildConfigs();

            if (guildConfigs.Count == 0)
            {
                throw new BaseAPIException("No guilds registered");
            }
            foreach (GuildConfig guildConfig in guildConfigs)
            {
                if (await currentIdentity.HasPermissionOnGuild(DiscordPermission.Moderator, guildConfig.GuildId))
                {
                    modGuilds.Add(guildConfig.GuildId.ToString());
                    guildViews.Add(new DiscordGuildView(_discordAPI.FetchGuildInfo(guildConfig.GuildId, CacheBehavior.Default)));
                }
            }
            if (modGuilds.Count == 0)
            {
                return(Unauthorized());
            }

            DiscordUserView searchedUser = DiscordUserView.CreateOrDefault(await _discordAPI.FetchUserInfo(userId, CacheBehavior.IgnoreButCacheOnError));

            // invites
            // ===============================================================================================
            InviteRepository inviteRepository = InviteRepository.CreateDefault(_serviceProvider);

            List <UserInviteExpandedView> invited = new();

            foreach (UserInvite invite in await inviteRepository.GetInvitedForUser(userId))
            {
                if (!modGuilds.Contains(invite.GuildId.ToString()))
                {
                    continue;
                }
                invited.Add(new UserInviteExpandedView(
                                invite,
                                await _discordAPI.FetchUserInfo(invite.JoinedUserId, CacheBehavior.OnlyCache),
                                await _discordAPI.FetchUserInfo(invite.InviteIssuerId, CacheBehavior.OnlyCache)
                                ));
            }

            List <UserInviteExpandedView> invitedBy = new();

            foreach (UserInvite invite in await inviteRepository.GetusedInvitesForUser(userId))
            {
                if (!modGuilds.Contains(invite.GuildId.ToString()))
                {
                    continue;
                }
                invitedBy.Add(new UserInviteExpandedView(
                                  invite,
                                  await _discordAPI.FetchUserInfo(invite.JoinedUserId, CacheBehavior.OnlyCache),
                                  await _discordAPI.FetchUserInfo(invite.InviteIssuerId, CacheBehavior.OnlyCache)
                                  ));
            }

            // mappings
            // ===============================================================================================
            UserMapRepository userMapRepository         = UserMapRepository.CreateDefault(_serviceProvider, currentIdentity);
            List <UserMappingExpandedView> userMappings = new();

            foreach (UserMapping userMapping in await userMapRepository.GetUserMapsByUser(userId))
            {
                if (!modGuilds.Contains(userMapping.GuildId.ToString()))
                {
                    continue;
                }
                userMappings.Add(new UserMappingExpandedView(
                                     userMapping,
                                     await _discordAPI.FetchUserInfo(userMapping.UserA, CacheBehavior.OnlyCache),
                                     await _discordAPI.FetchUserInfo(userMapping.UserB, CacheBehavior.OnlyCache),
                                     await _discordAPI.FetchUserInfo(userMapping.CreatorUserId, CacheBehavior.OnlyCache)
                                     ));
            }

            ModCaseRepository             modCaseRepository             = ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity);
            AutoModerationEventRepository autoModerationEventRepository = AutoModerationEventRepository.CreateDefault(_serviceProvider);
            UserNoteRepository            userNoteRepository            = UserNoteRepository.CreateDefault(_serviceProvider, currentIdentity);

            List <CaseView> modCases = (await modCaseRepository.GetCasesForUser(userId)).Where(x => modGuilds.Contains(x.GuildId.ToString())).Select(x => new CaseView(x)).ToList();
            List <AutoModerationEventView> modEvents = (await autoModerationEventRepository.GetAllEventsForUser(userId)).Where(x => modGuilds.Contains(x.GuildId.ToString())).Select(x => new AutoModerationEventView(x)).ToList();
            List <UserNoteView>            userNotes = (await userNoteRepository.GetUserNotesByUser(userId)).Where(x => modGuilds.Contains(x.GuildId.ToString())).Select(x => new UserNoteView(x)).ToList();

            return(Ok(new
            {
                guilds = guildViews,
                user = searchedUser,
                invited,
                invitedBy,
                modCases,
                modEvents,
                userMappings,
                userNotes
            }));
        }
Example #28
0
 public GuildConfigurationModule(GuildConfigRepository repository, CommandService commandService)
 {
     this._repository     = repository;
     this._commandService = commandService;
 }
        private async Task AnnounceModCase(ModCase modCase, IUser actor, bool announcePublic, bool announceDm, RestAction action)
        {
            using var scope = _serviceProvider.CreateScope();

            _logger.LogInformation($"Announcing modcase {modCase.Id} in guild {modCase.GuildId}.");

            var translator = scope.ServiceProvider.GetRequiredService <Translator>();

            IUser caseUser = await _discordAPI.FetchUserInfo(modCase.UserId, CacheBehavior.Default);

            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);

            translator.SetContext(guildConfig);

            if (announceDm && action != RestAction.Deleted)
            {
                _logger.LogInformation($"Sending dm notification to {modCase.UserId} for case {modCase.GuildId}/{modCase.CaseId}");

                try
                {
                    IGuild guild   = _discordAPI.FetchGuildInfo(modCase.GuildId, CacheBehavior.Default);
                    string message = string.Empty;
                    switch (modCase.PunishmentType)
                    {
                    case PunishmentType.Mute:
                        if (modCase.PunishedUntil.HasValue)
                        {
                            message = translator.T().NotificationModcaseDMMuteTemp(modCase, guild, _config.GetBaseUrl());
                        }
                        else
                        {
                            message = translator.T().NotificationModcaseDMMutePerm(guild, _config.GetBaseUrl());
                        }
                        break;

                    case PunishmentType.Kick:
                        message = translator.T().NotificationModcaseDMKick(guild, _config.GetBaseUrl());
                        break;

                    case PunishmentType.Ban:
                        if (modCase.PunishedUntil.HasValue)
                        {
                            message = translator.T().NotificationModcaseDMBanTemp(modCase, guild, _config.GetBaseUrl());
                        }
                        else
                        {
                            message = translator.T().NotificationModcaseDMBanPerm(guild, _config.GetBaseUrl());
                        }
                        break;

                    default:
                        message = translator.T().NotificationModcaseDMWarn(guild, _config.GetBaseUrl());
                        break;
                    }
                    await _discordAPI.SendDmMessage(modCase.UserId, message);
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing modcase {modCase.GuildId}/{modCase.CaseId} in DMs to {modCase.UserId}.");
                }
            }

            if (!string.IsNullOrEmpty(guildConfig.ModPublicNotificationWebhook) && announcePublic)
            {
                _logger.LogInformation($"Sending public webhook for modcase {modCase.GuildId}/{modCase.CaseId} to {guildConfig.ModPublicNotificationWebhook}.");

                try
                {
                    EmbedBuilder embed = await modCase.CreateModcaseEmbed(action, actor, scope.ServiceProvider, caseUser, false);

                    await _discordAPI.ExecuteWebhook(guildConfig.ModPublicNotificationWebhook, embed.Build(), $"<@{modCase.UserId}>");
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing modcase {modCase.GuildId}/{modCase.CaseId} public to {guildConfig.ModPublicNotificationWebhook}.");
                }
            }

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                _logger.LogInformation($"Sending internal webhook for modcase {modCase.GuildId}/{modCase.CaseId} to {guildConfig.ModInternalNotificationWebhook}.");

                try
                {
                    EmbedBuilder embed = await modCase.CreateModcaseEmbed(action, actor, scope.ServiceProvider, caseUser, true);

                    await _discordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build(), $"<@{modCase.UserId}>");
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing modcase {modCase.GuildId}/{modCase.CaseId} internal to {guildConfig.ModInternalNotificationWebhook}.");
                }
            }
        }
Example #30
0
 public QuotedCommandHandler(IServiceProvider provider, DiscordSocketClient client,
                             CommandServiceConfig commandServiceConfig, CommandHandlerOptions options, CustomModuleBuilder moduleBuilder,
                             IEnumerable <IPluginFactory> pluginFactories,
                             ILogger <PrefixCommandHandler> logger, CommandService commandService, GuildConfigRepository guildConfigRepository, RepeatRepository repeatRepository)
     : base(provider, client, commandServiceConfig, options, moduleBuilder, pluginFactories, logger, commandService, guildConfigRepository, repeatRepository)
 {
     base.logger = logger;
 }