Refactor permission utils to properly account for lack of channel access
This commit is contained in:
parent
f97ceac1fb
commit
ee9c87a29f
@ -9,6 +9,7 @@ using Autofac;
|
|||||||
|
|
||||||
using DSharpPlus;
|
using DSharpPlus;
|
||||||
using DSharpPlus.Entities;
|
using DSharpPlus.Entities;
|
||||||
|
using DSharpPlus.Exceptions;
|
||||||
|
|
||||||
using PluralKit.Bot.Utils;
|
using PluralKit.Bot.Utils;
|
||||||
using PluralKit.Core;
|
using PluralKit.Core;
|
||||||
@ -281,14 +282,27 @@ namespace PluralKit.Bot
|
|||||||
throw new PKError("You do not have permission to access this information.");
|
throw new PKError("You do not have permission to access this information.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public DiscordChannel MatchChannel()
|
public async Task<DiscordChannel> MatchChannel()
|
||||||
{
|
{
|
||||||
if (!MentionUtils.TryParseChannel(PeekArgument(), out var channel)) return null;
|
if (!MentionUtils.TryParseChannel(PeekArgument(), out var channel))
|
||||||
var discordChannel = _rest.GetChannelAsync(channel).GetAwaiter().GetResult();
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var discordChannel = await _shard.GetChannelAsync(channel);
|
||||||
if (discordChannel.Type != ChannelType.Text) return null;
|
if (discordChannel.Type != ChannelType.Text) return null;
|
||||||
|
|
||||||
PopArgument();
|
PopArgument();
|
||||||
return discordChannel;
|
return discordChannel;
|
||||||
}
|
}
|
||||||
|
catch (NotFoundException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,7 +25,7 @@ namespace PluralKit.Bot
|
|||||||
|
|
||||||
DiscordChannel channel = null;
|
DiscordChannel channel = null;
|
||||||
if (ctx.HasNext())
|
if (ctx.HasNext())
|
||||||
channel = ctx.MatchChannel() ?? throw new PKSyntaxError("You must pass a #channel to set.");
|
channel = await ctx.MatchChannel() ?? throw new PKSyntaxError("You must pass a #channel to set.");
|
||||||
if (channel != null && channel.GuildId != ctx.Guild.Id) throw new PKError("That channel is not in this server!");
|
if (channel != null && channel.GuildId != ctx.Guild.Id) throw new PKError("That channel is not in this server!");
|
||||||
|
|
||||||
var cfg = await _data.GetOrCreateGuildConfig(ctx.Guild.Id);
|
var cfg = await _data.GetOrCreateGuildConfig(ctx.Guild.Id);
|
||||||
@ -48,7 +48,7 @@ namespace PluralKit.Bot
|
|||||||
else if (!ctx.HasNext()) throw new PKSyntaxError("You must pass one or more #channels.");
|
else if (!ctx.HasNext()) throw new PKSyntaxError("You must pass one or more #channels.");
|
||||||
else while (ctx.HasNext())
|
else while (ctx.HasNext())
|
||||||
{
|
{
|
||||||
var channel = ctx.MatchChannel() ?? throw new PKSyntaxError($"Channel \"{ctx.PopArgument().SanitizeMentions()}\" not found.");
|
var channel = await ctx.MatchChannel() ?? throw new PKSyntaxError($"Channel \"{ctx.PopArgument().SanitizeMentions()}\" not found.");
|
||||||
if (channel.GuildId != ctx.Guild.Id) throw new PKError($"Channel {ctx.Guild.Id} is not in this server.");
|
if (channel.GuildId != ctx.Guild.Id) throw new PKError($"Channel {ctx.Guild.Id} is not in this server.");
|
||||||
affectedChannels.Add(channel);
|
affectedChannels.Add(channel);
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ namespace PluralKit.Bot
|
|||||||
else if (!ctx.HasNext()) throw new PKSyntaxError("You must pass one or more #channels.");
|
else if (!ctx.HasNext()) throw new PKSyntaxError("You must pass one or more #channels.");
|
||||||
else while (ctx.HasNext())
|
else while (ctx.HasNext())
|
||||||
{
|
{
|
||||||
var channel = ctx.MatchChannel() ?? throw new PKSyntaxError($"Channel \"{ctx.PopArgument().SanitizeMentions()}\" not found.");
|
var channel = await ctx.MatchChannel() ?? throw new PKSyntaxError($"Channel \"{ctx.PopArgument().SanitizeMentions()}\" not found.");
|
||||||
if (channel.GuildId != ctx.Guild.Id) throw new PKError($"Channel {ctx.Guild.Id} is not in this server.");
|
if (channel.GuildId != ctx.Guild.Id) throw new PKError($"Channel {ctx.Guild.Id} is not in this server.");
|
||||||
affectedChannels.Add(channel);
|
affectedChannels.Add(channel);
|
||||||
}
|
}
|
||||||
|
@ -15,46 +15,53 @@ namespace PluralKit.Bot
|
|||||||
public static DiscordColor Red = new DiscordColor(0xef4b3d);
|
public static DiscordColor Red = new DiscordColor(0xef4b3d);
|
||||||
public static DiscordColor Gray = new DiscordColor(0x979c9f);
|
public static DiscordColor Gray = new DiscordColor(0x979c9f);
|
||||||
|
|
||||||
|
public static Permissions DM_PERMISSIONS = (Permissions) 0b00000_1000110_1011100110000_000000;
|
||||||
|
|
||||||
public static string NameAndMention(this DiscordUser user) {
|
public static string NameAndMention(this DiscordUser user) {
|
||||||
return $"{user.Username}#{user.Discriminator} ({user.Mention})";
|
return $"{user.Username}#{user.Discriminator} ({user.Mention})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We funnel all "permissions from DiscordMember" calls through here
|
||||||
|
// This way we can ensure we do the read permission correction everywhere
|
||||||
|
private static Permissions PermissionsInGuild(DiscordChannel channel, DiscordMember member)
|
||||||
|
{
|
||||||
|
var permissions = channel.PermissionsFor(member);
|
||||||
|
|
||||||
|
// This method doesn't account for channels without read permissions
|
||||||
|
// If we don't have read permissions in the channel, we don't have *any* permissions
|
||||||
|
if ((permissions & Permissions.AccessChannels) != Permissions.AccessChannels)
|
||||||
|
return Permissions.None;
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<Permissions> PermissionsIn(this DiscordChannel channel, DiscordUser user)
|
public static async Task<Permissions> PermissionsIn(this DiscordChannel channel, DiscordUser user)
|
||||||
{
|
{
|
||||||
if (channel.Guild != null)
|
// Just delegates to PermissionsInSync, but handles the case of a non-member User in a guild properly
|
||||||
{
|
// This is a separate method because it requires an async call
|
||||||
var member = await channel.Guild.GetMemberAsync(user.Id);
|
if (channel.Guild != null && !(user is DiscordMember))
|
||||||
return member.PermissionsIn(channel);
|
return PermissionsInSync(channel, await channel.Guild.GetMemberAsync(user.Id));
|
||||||
}
|
return PermissionsInSync(channel, user);
|
||||||
|
|
||||||
if (channel.Type == ChannelType.Private)
|
|
||||||
return (Permissions) 0b00000_1000110_1011100110000_000000;
|
|
||||||
|
|
||||||
return Permissions.None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same as PermissionsIn, but always synchronous. DiscordUser must be a DiscordMember if channel is in guild.
|
||||||
public static Permissions PermissionsInSync(this DiscordChannel channel, DiscordUser user)
|
public static Permissions PermissionsInSync(this DiscordChannel channel, DiscordUser user)
|
||||||
{
|
{
|
||||||
if (user is DiscordMember dm && channel.Guild != null)
|
if (channel.Guild != null && !(user is DiscordMember))
|
||||||
return dm.PermissionsIn(channel);
|
throw new ArgumentException("Function was passed a guild channel but a non-member DiscordUser");
|
||||||
|
|
||||||
if (channel.Type == ChannelType.Private)
|
|
||||||
return (Permissions) 0b00000_1000110_1011100110000_000000;
|
|
||||||
|
|
||||||
|
if (user is DiscordMember m) return PermissionsInGuild(channel, m);
|
||||||
|
if (channel.Type == ChannelType.Private) return DM_PERMISSIONS;
|
||||||
return Permissions.None;
|
return Permissions.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Permissions BotPermissions(this DiscordChannel channel)
|
public static Permissions BotPermissions(this DiscordChannel channel)
|
||||||
{
|
{
|
||||||
|
// TODO: can we get a CurrentMember somehow without a guild context?
|
||||||
|
// at least, without somehow getting a DiscordClient reference as an arg(which I don't want to do)
|
||||||
if (channel.Guild != null)
|
if (channel.Guild != null)
|
||||||
{
|
return PermissionsInSync(channel, channel.Guild.CurrentMember);
|
||||||
var member = channel.Guild.CurrentMember;
|
if (channel.Type == ChannelType.Private) return DM_PERMISSIONS;
|
||||||
return channel.PermissionsFor(member);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel.Type == ChannelType.Private)
|
|
||||||
return (Permissions) 0b00000_1000110_1011100110000_000000;
|
|
||||||
|
|
||||||
return Permissions.None;
|
return Permissions.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user