Skip to content

Commit

Permalink
Merge pull request #1022 from PaulBraetz/vc-status-moderation
Browse files Browse the repository at this point in the history
Voice channel status moderation against blocklist patterns
  • Loading branch information
patrickklaeren authored Aug 7, 2024
2 parents b4324e5 + 9a3f09d commit 5bbde45
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
9 changes: 9 additions & 0 deletions src/Modix.Services/Core/DiscordSocketListeningBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Task StartAsync(
DiscordSocketClient.AuditLogCreated += OnAuditLogCreatedAsync;
DiscordSocketClient.ChannelCreated += OnChannelCreatedAsync;
DiscordSocketClient.ChannelUpdated += OnChannelUpdatedAsync;
DiscordSocketClient.VoiceChannelStatusUpdated += OnVoiceChannelStatusUpdated;
DiscordSocketClient.GuildAvailable += OnGuildAvailableAsync;
DiscordSocketClient.GuildMemberUpdated += OnGuildMemberUpdatedAsync;
DiscordSocketClient.InteractionCreated += OnInteractionCreatedAsync;
Expand Down Expand Up @@ -61,6 +62,7 @@ public Task StopAsync(
DiscordSocketClient.AuditLogCreated -= OnAuditLogCreatedAsync;
DiscordSocketClient.ChannelCreated -= OnChannelCreatedAsync;
DiscordSocketClient.ChannelUpdated -= OnChannelUpdatedAsync;
DiscordSocketClient.VoiceChannelStatusUpdated -= OnVoiceChannelStatusUpdated;
DiscordSocketClient.GuildAvailable -= OnGuildAvailableAsync;
DiscordSocketClient.GuildMemberUpdated -= OnGuildMemberUpdatedAsync;
DiscordSocketClient.InteractionCreated += OnInteractionCreatedAsync;
Expand Down Expand Up @@ -103,6 +105,13 @@ private Task OnChannelCreatedAsync(SocketChannel channel)
return Task.CompletedTask;
}

private Task OnVoiceChannelStatusUpdated(Cacheable<SocketVoiceChannel, ulong> channel, string oldStatus, string newStatus)
{
MessageDispatcher.Dispatch(new VoiceChannelStatusUpdatedNotification(channel, oldStatus, newStatus));

return Task.CompletedTask;
}

private Task OnChannelUpdatedAsync(SocketChannel oldChannel, SocketChannel newChannel)
{
MessageDispatcher.Dispatch(new ChannelUpdatedNotification(oldChannel, newChannel));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;

using Discord.WebSocket;

namespace Discord
{
/// <summary>
/// Describes an application-wide notification that occurs when <see cref="IBaseSocketClient.VoiceChannelStatusUpdated"/> is raised.
/// </summary>
public class VoiceChannelStatusUpdatedNotification
{
/// <summary>
/// Constructs a new <see cref="VoiceChannelStatusUpdatedNotification"/> from the given values.
/// </summary>
/// <param name="channel">The value to use for <see cref="Channel"/>.</param>
/// <param name="oldStatus">The value to use for <see cref="OldStatus"/>.</param>
/// <param name="newStatus">The value to use for <see cref="NewStatus"/>.</param>
/// <exception cref="ArgumentNullException">Throws for <paramref name="oldStatus"/>.</exception>
/// <exception cref="ArgumentNullException">Throws for <paramref name="newStatus"/>.</exception>
public VoiceChannelStatusUpdatedNotification(Cacheable<SocketVoiceChannel, ulong> channel, string oldStatus, string newStatus)
{
ArgumentNullException.ThrowIfNull(oldStatus);
ArgumentNullException.ThrowIfNull(newStatus);

Channel = channel;
OldStatus = oldStatus;
NewStatus = newStatus;
}
/// <summary>
/// The voice channel whose status was updated.
/// </summary>
public Cacheable<SocketVoiceChannel, ulong> Channel { get; }
/// <summary>
/// The old voice channel status.
/// </summary>
public string OldStatus { get; }
/// <summary>
/// The new voice channel status.
/// </summary>
public string NewStatus { get; }
}
}
36 changes: 32 additions & 4 deletions src/Modix.Services/Moderation/MessageContentCheckBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ namespace Modix.Services.Moderation
{
public class MessageContentCheckBehaviour :
INotificationHandler<MessageReceivedNotification>,
INotificationHandler<MessageUpdatedNotification>
INotificationHandler<MessageUpdatedNotification>,
INotificationHandler<VoiceChannelStatusUpdatedNotification>
{
private readonly IDesignatedChannelService _designatedChannelService;
private readonly IAuthorizationService _authorizationService;
Expand Down Expand Up @@ -43,6 +44,29 @@ public Task HandleNotificationAsync(MessageReceivedNotification notification,
public Task HandleNotificationAsync(MessageUpdatedNotification notification,
CancellationToken cancellationToken = default)
=> TryCheckMessageAsync(notification.NewMessage);
public async Task HandleNotificationAsync(VoiceChannelStatusUpdatedNotification notification,
CancellationToken cancellationToken = default)
{
var channel = await notification.Channel.GetOrDownloadAsync();
var newStatus = notification.NewStatus;
var isBlocked = await IsContentBlocked(channel, newStatus);

if (!isBlocked)
{
return;
}

Log.Debug("Status {newStatus} from voice channel {channelId} is going to be deleted", newStatus, channel.Id);

//Setting to old status seems risky as there is a race condition
//between two consecutive edits being moderated in parallel.
//May client events being fired in parallel?
await channel.SetStatusAsync(string.Empty);

Log.Debug("Status {newStatus} from voice channel {channelId} was deleted because it contains blocked content", newStatus, channel.Id);

await channel.SendMessageAsync("Sorry, the new status contained blocked content and has been removed!");
}

private async Task TryCheckMessageAsync(IMessage message)
{
Expand Down Expand Up @@ -91,16 +115,20 @@ await message.Channel.SendMessageAsync(
$"Sorry {author.Mention} your message contained blocked content and has been removed!");
}

private async Task<bool> IsContentBlocked(IGuildChannel channel, IMessage message)
private Task<bool> IsContentBlocked(SocketVoiceChannel channel, string status) =>
IsContentBlocked(channel.Guild.Id, status);
private Task<bool> IsContentBlocked(IGuildChannel channel, IMessage message) =>
IsContentBlocked(channel.GuildId, message.Content);
private async Task<bool> IsContentBlocked(ulong guildId, string messageContent)
{
var patterns = await _messageContentPatternService.GetPatterns(channel.GuildId);
var patterns = await _messageContentPatternService.GetPatterns(guildId);

foreach (var patternToCheck in patterns.Where(x => x.Type == MessageContentPatternType.Blocked))
{
// If the content is not blocked, we can just continue to check the next
// blocked pattern

var (containsBlockedPattern, blockedMatches) = GetContentMatches(message.Content, patternToCheck);
var (containsBlockedPattern, blockedMatches) = GetContentMatches(messageContent, patternToCheck);

if (!containsBlockedPattern)
{
Expand Down

0 comments on commit 5bbde45

Please sign in to comment.