You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
8.0 KiB
175 lines
8.0 KiB
using System.Runtime.CompilerServices;
|
|
|
|
namespace Discord
|
|
{
|
|
internal static class Permissions
|
|
{
|
|
public const int MaxBits = 53;
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static PermValue GetValue(ulong allow, ulong deny, ChannelPermission flag)
|
|
=> GetValue(allow, deny, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static PermValue GetValue(ulong allow, ulong deny, GuildPermission flag)
|
|
=> GetValue(allow, deny, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static PermValue GetValue(ulong allow, ulong deny, ulong flag)
|
|
{
|
|
if (HasFlag(allow, flag))
|
|
return PermValue.Allow;
|
|
else if (HasFlag(deny, flag))
|
|
return PermValue.Deny;
|
|
else
|
|
return PermValue.Inherit;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool GetValue(ulong value, ChannelPermission flag)
|
|
=> GetValue(value, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool GetValue(ulong value, GuildPermission flag)
|
|
=> GetValue(value, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool GetValue(ulong value, ulong flag) => HasFlag(value, flag);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetValue(ref ulong rawValue, bool? value, ChannelPermission flag)
|
|
=> SetValue(ref rawValue, value, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetValue(ref ulong rawValue, bool? value, GuildPermission flag)
|
|
=> SetValue(ref rawValue, value, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetValue(ref ulong rawValue, bool? value, ulong flag)
|
|
{
|
|
if (value.HasValue)
|
|
{
|
|
if (value == true)
|
|
SetFlag(ref rawValue, flag);
|
|
else
|
|
UnsetFlag(ref rawValue, flag);
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, ChannelPermission flag)
|
|
=> SetValue(ref allow, ref deny, value, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, GuildPermission flag)
|
|
=> SetValue(ref allow, ref deny, value, (ulong)flag);
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, ulong flag)
|
|
{
|
|
if (value.HasValue)
|
|
{
|
|
switch (value)
|
|
{
|
|
case PermValue.Allow:
|
|
SetFlag(ref allow, flag);
|
|
UnsetFlag(ref deny, flag);
|
|
break;
|
|
case PermValue.Deny:
|
|
UnsetFlag(ref allow, flag);
|
|
SetFlag(ref deny, flag);
|
|
break;
|
|
default:
|
|
UnsetFlag(ref allow, flag);
|
|
UnsetFlag(ref deny, flag);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static bool HasFlag(ulong value, ulong flag) => (value & flag) == flag;
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SetFlag(ref ulong value, ulong flag) => value |= flag;
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void UnsetFlag(ref ulong value, ulong flag) => value &= ~flag;
|
|
|
|
public static ChannelPermissions ToChannelPerms(IGuildChannel channel, ulong guildPermissions)
|
|
=> new ChannelPermissions(guildPermissions & ChannelPermissions.All(channel).RawValue);
|
|
public static ulong ResolveGuild(IGuild guild, IGuildUser user)
|
|
{
|
|
ulong resolvedPermissions = 0;
|
|
|
|
if (user.Id == guild.OwnerId)
|
|
resolvedPermissions = GuildPermissions.All.RawValue; //Owners always have all permissions
|
|
else if (user.IsWebhook)
|
|
resolvedPermissions = GuildPermissions.Webhook.RawValue;
|
|
else
|
|
{
|
|
foreach (var roleId in user.RoleIds)
|
|
resolvedPermissions |= guild.GetRole(roleId)?.Permissions.RawValue ?? 0;
|
|
if (GetValue(resolvedPermissions, GuildPermission.Administrator))
|
|
resolvedPermissions = GuildPermissions.All.RawValue; //Administrators always have all permissions
|
|
}
|
|
return resolvedPermissions;
|
|
}
|
|
|
|
/*public static ulong ResolveChannel(IGuildUser user, IGuildChannel channel)
|
|
{
|
|
return ResolveChannel(user, channel, ResolveGuild(user));
|
|
}*/
|
|
public static ulong ResolveChannel(IGuild guild, IGuildUser user, IGuildChannel channel, ulong guildPermissions)
|
|
{
|
|
ulong resolvedPermissions = 0;
|
|
|
|
ulong mask = ChannelPermissions.All(channel).RawValue;
|
|
if (GetValue(guildPermissions, GuildPermission.Administrator)) //Includes owner
|
|
resolvedPermissions = mask; //Owners and administrators always have all permissions
|
|
else
|
|
{
|
|
//Start with this user's guild permissions
|
|
resolvedPermissions = guildPermissions;
|
|
|
|
//Give/Take Everyone permissions
|
|
var perms = channel.GetPermissionOverwrite(guild.EveryoneRole);
|
|
if (perms != null)
|
|
resolvedPermissions = (resolvedPermissions & ~perms.Value.DenyValue) | perms.Value.AllowValue;
|
|
|
|
//Give/Take Role permissions
|
|
ulong deniedPermissions = 0UL, allowedPermissions = 0UL;
|
|
foreach (var roleId in user.RoleIds)
|
|
{
|
|
IRole role;
|
|
if (roleId != guild.EveryoneRole.Id && (role = guild.GetRole(roleId)) != null)
|
|
{
|
|
perms = channel.GetPermissionOverwrite(role);
|
|
if (perms != null)
|
|
{
|
|
allowedPermissions |= perms.Value.AllowValue;
|
|
deniedPermissions |= perms.Value.DenyValue;
|
|
}
|
|
}
|
|
}
|
|
resolvedPermissions = (resolvedPermissions & ~deniedPermissions) | allowedPermissions;
|
|
|
|
//Give/Take User permissions
|
|
perms = channel.GetPermissionOverwrite(user);
|
|
if (perms != null)
|
|
resolvedPermissions = (resolvedPermissions & ~perms.Value.DenyValue) | perms.Value.AllowValue;
|
|
|
|
if (channel is ITextChannel)
|
|
{
|
|
if (!GetValue(resolvedPermissions, ChannelPermission.ViewChannel))
|
|
{
|
|
//No read permission on a text channel removes all other permissions
|
|
resolvedPermissions = 0;
|
|
}
|
|
else if (!GetValue(resolvedPermissions, ChannelPermission.SendMessages))
|
|
{
|
|
//No send permissions on a text channel removes all send-related permissions
|
|
resolvedPermissions &= ~(ulong)ChannelPermission.SendTTSMessages;
|
|
resolvedPermissions &= ~(ulong)ChannelPermission.MentionEveryone;
|
|
resolvedPermissions &= ~(ulong)ChannelPermission.EmbedLinks;
|
|
resolvedPermissions &= ~(ulong)ChannelPermission.AttachFiles;
|
|
}
|
|
}
|
|
resolvedPermissions &= mask; //Ensure we didn't get any permissions this channel doesn't support (from guildPerms, for example)
|
|
}
|
|
|
|
return resolvedPermissions;
|
|
}
|
|
}
|
|
}
|