fix(bot): only allow proxying in known-supported channel types

This is so that new channel types added by Discord (that may or may not
support the features we need for proxying to work) don't throw piles of
error codes at users when they try to proxy.
This commit is contained in:
Iris System 2023-06-28 14:38:50 +12:00
parent a0fa03599b
commit 6b14c50f09
4 changed files with 44 additions and 10 deletions

View File

@ -14,7 +14,10 @@ public record Channel
GuildNewsThread = 10, GuildNewsThread = 10,
GuildPublicThread = 11, GuildPublicThread = 11,
GuildPrivateThread = 12, GuildPrivateThread = 12,
GuildStageVoice = 13 GuildStageVoice = 13,
GuildDirectory = 14,
GuildForum = 15,
GuildMedia = 16,
} }
public ulong Id { get; init; } public ulong Id { get; init; }

View File

@ -248,10 +248,10 @@ public class Checks
// Run everything through the checks, catch the ProxyCheckFailedException, and reply with the error message. // Run everything through the checks, catch the ProxyCheckFailedException, and reply with the error message.
try try
{ {
_proxy.ShouldProxy(channel, msg, context); _proxy.ShouldProxy(channel, rootChannel, msg, context);
_matcher.TryMatch(context, autoproxySettings, members, out var match, msg.Content, msg.Attachments.Length > 0, true, ctx.Config.CaseSensitiveProxyTags); _matcher.TryMatch(context, autoproxySettings, members, out var match, msg.Content, msg.Attachments.Length > 0, true, ctx.Config.CaseSensitiveProxyTags);
var canProxy = await _proxy.CanProxy(channel, msg, context); var canProxy = await _proxy.CanProxy(channel, rootChannel, msg, context);
if (canProxy != null) if (canProxy != null)
{ {
await ctx.Reply(canProxy); await ctx.Reply(canProxy);

View File

@ -57,7 +57,9 @@ public class ProxyService
public async Task<bool> HandleIncomingMessage(MessageCreateEvent message, MessageContext ctx, public async Task<bool> HandleIncomingMessage(MessageCreateEvent message, MessageContext ctx,
Guild guild, Channel channel, bool allowAutoproxy, PermissionSet botPermissions) Guild guild, Channel channel, bool allowAutoproxy, PermissionSet botPermissions)
{ {
if (!ShouldProxy(channel, message, ctx)) var rootChannel = await _cache.GetRootChannel(message.ChannelId);
if (!ShouldProxy(channel, rootChannel, message, ctx))
return false; return false;
var autoproxySettings = await _repo.GetAutoproxySettings(ctx.SystemId.Value, guild.Id, null); var autoproxySettings = await _repo.GetAutoproxySettings(ctx.SystemId.Value, guild.Id, null);
@ -72,8 +74,6 @@ public class ProxyService
return false; return false;
} }
var rootChannel = await _cache.GetRootChannel(message.ChannelId);
List<ProxyMember> members; List<ProxyMember> members;
// Fetch members and try to match to a specific member // Fetch members and try to match to a specific member
using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime)) using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime))
@ -82,7 +82,7 @@ public class ProxyService
if (!_matcher.TryMatch(ctx, autoproxySettings, members, out var match, message.Content, message.Attachments.Length > 0, if (!_matcher.TryMatch(ctx, autoproxySettings, members, out var match, message.Content, message.Attachments.Length > 0,
allowAutoproxy, ctx.CaseSensitiveProxyTags)) return false; allowAutoproxy, ctx.CaseSensitiveProxyTags)) return false;
var canProxy = await CanProxy(channel, message, ctx); var canProxy = await CanProxy(channel, rootChannel, message, ctx);
if (canProxy != null) if (canProxy != null)
{ {
if (ctx.ProxyErrorMessageEnabled) if (ctx.ProxyErrorMessageEnabled)
@ -109,8 +109,32 @@ public class ProxyService
return true; return true;
} }
public async Task<string> CanProxy(Channel channel, Message msg, MessageContext ctx) #pragma warning disable CA1822 // Mark members as static
internal bool CanProxyInChannel(Channel ch, bool isRootChannel = false)
#pragma warning restore CA1822 // Mark members as static
{ {
// this is explicitly selecting known channel types so that when Discord add new
// ones, users don't get flooded with error codes if that new channel type doesn't
// support a feature we need for proxying
return ch.Type switch
{
Channel.ChannelType.GuildText => true,
Channel.ChannelType.GuildPublicThread => true,
Channel.ChannelType.GuildPrivateThread => true,
Channel.ChannelType.GuildNews => true,
Channel.ChannelType.GuildNewsThread => true,
Channel.ChannelType.GuildVoice => true,
Channel.ChannelType.GuildStageVoice => true,
Channel.ChannelType.GuildForum => isRootChannel,
_ => false,
};
}
public async Task<string> CanProxy(Channel channel, Channel rootChannel, Message msg, MessageContext ctx)
{
if (!(CanProxyInChannel(channel) && CanProxyInChannel(rootChannel, true)))
return $"PluralKit cannot proxy messages in this type of channel.";
// Check if the message does not go over any Discord Nitro limits // Check if the message does not go over any Discord Nitro limits
if (msg.Content != null && msg.Content.Length > 2000) if (msg.Content != null && msg.Content.Length > 2000)
{ {
@ -132,7 +156,7 @@ public class ProxyService
return null; return null;
} }
public bool ShouldProxy(Channel channel, Message msg, MessageContext ctx) public bool ShouldProxy(Channel channel, Channel rootChannel, Message msg, MessageContext ctx)
{ {
// Make sure author has a system // Make sure author has a system
if (ctx.SystemId == null) if (ctx.SystemId == null)

View File

@ -105,7 +105,14 @@ public class WebhookCacheService
{ {
try try
{ {
return await _rest.GetChannelWebhooks(channelId); var webhooks = await _rest.GetChannelWebhooks(channelId);
if (webhooks != null)
return webhooks;
// Getting a 404 / null response from the above generally means the channel type does
// not support webhooks - this is detected elsewhere for proxying purposes, let's just
// return an empty array here
return new Webhook[0];
} }
catch (HttpRequestException e) catch (HttpRequestException e)
{ {