From e30e18b89dac2856f10279243ed83bf64967a79f Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 26 Feb 2026 08:58:36 +0100 Subject: [PATCH] UApi/models: permissions? --- .../Constants/Permissions.cs | 60 +++++++++++++++++++ extra/admin-api/Spacebar.UApi/Program.cs | 2 + .../Services/PermissionService.cs | 41 +++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 extra/admin-api/Models/Spacebar.Models.Generic/Constants/Permissions.cs create mode 100644 extra/admin-api/Spacebar.UApi/Services/PermissionService.cs diff --git a/extra/admin-api/Models/Spacebar.Models.Generic/Constants/Permissions.cs b/extra/admin-api/Models/Spacebar.Models.Generic/Constants/Permissions.cs new file mode 100644 index 000000000..03b4112a1 --- /dev/null +++ b/extra/admin-api/Models/Spacebar.Models.Generic/Constants/Permissions.cs @@ -0,0 +1,60 @@ +namespace Spacebar.Models.Generic.Constants; + +[Flags] +public enum Permissions : ulong { + CreateInstantInvite = 1UL << 0, + KickMembers = 1UL << 1, + BanMembers = 1UL << 2, + Administrator = 1UL << 3, + ManageChannels = 1UL << 4, + ManageGuild = 1UL << 5, + AddReactions = 1UL << 6, + ViewAuditLog = 1UL << 7, + PrioritySpeaker = 1UL << 8, + Stream = 1UL << 9, + ViewChannel = 1UL << 10, + SendMessages = 1UL << 11, + SendTtsMessages = 1UL << 12, + ManageMessages = 1UL << 13, + EmbedLinks = 1UL << 14, + AttachFiles = 1UL << 15, + ReadMessageHistory = 1UL << 16, + MentionEveryone = 1UL << 17, + UseExternalEmojis = 1UL << 18, + ViewGuildInsights = 1UL << 19, + Connect = 1UL << 20, + Speak = 1UL << 21, + MuteMembers = 1UL << 22, + DeafenMembers = 1UL << 23, + MoveMembers = 1UL << 24, + UseVad = 1UL << 25, + ChangeNickname = 1UL << 26, + ManageNicknames = 1UL << 27, + ManageRoles = 1UL << 28, + ManageWebhooks = 1UL << 29, + ManageExpressions = 1UL << 30, + UseApplicationCommands = 1UL << 31, + RequestToSpeak = 1UL << 32, + ManageEvents = 1UL << 33, + ManageThreads = 1UL << 34, + CreatePublicThreads = 1UL << 35, + CreatePrivateThreads = 1UL << 36, + UseExternalStickers = 1UL << 37, + SendMessagesInThreads = 1UL << 38, + UseEmbeddedActivities = 1UL << 39, + ModerateMembers = 1UL << 40, + ViewCreatorMonetizationAnalytics = 1UL << 41, + UseSoundboard = 1UL << 42, + CreateExpressions = 1UL << 43, + CreateEvents = 1UL << 44, + UseExternalSounds = 1UL << 45, + SendVoiceMessages = 1UL << 46, + + [Obsolete("Clyde is no longer available")] + UseClydeAi = 1UL << 47, + SetVoiceChannelStatus = 1UL << 48, + SendPolls = 1UL << 49, + UseExternalApps = 1UL << 50, + PinMessages = 1UL << 51, + BypassSlowmode = 1UL << 52 +} \ No newline at end of file diff --git a/extra/admin-api/Spacebar.UApi/Program.cs b/extra/admin-api/Spacebar.UApi/Program.cs index f6ce98299..afdb42ae8 100644 --- a/extra/admin-api/Spacebar.UApi/Program.cs +++ b/extra/admin-api/Spacebar.UApi/Program.cs @@ -8,6 +8,7 @@ using Spacebar.ConfigModel.Extensions; using Spacebar.Interop.Authentication; using Spacebar.Interop.Authentication.AspNetCore; using Spacebar.Models.Db.Contexts; +using Spacebar.Models.Generic.Constants; using Spacebar.UApi.Services; var builder = WebApplication.CreateBuilder(args); @@ -59,6 +60,7 @@ builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); var app = builder.Build(); diff --git a/extra/admin-api/Spacebar.UApi/Services/PermissionService.cs b/extra/admin-api/Spacebar.UApi/Services/PermissionService.cs new file mode 100644 index 000000000..033dbb205 --- /dev/null +++ b/extra/admin-api/Spacebar.UApi/Services/PermissionService.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore; +using Spacebar.Models.Db.Contexts; +using Spacebar.Models.Generic.Constants; + +namespace Spacebar.UApi.Services; + +public class PermissionService(SpacebarDbContext db) { + /// + /// Asserts that user has all the relevant guild permissions + /// + /// Permissions to require + /// Guild ID + /// Member ID + /// Has one or more missing permissions + public async Task AssertUserHasGuildPermission(Permissions permission, string guildId, string userId) { + var member = await db.Members + .Include(x => x.Roles) + .SingleAsync(x => x.Id == userId && x.GuildId == guildId); + + if (member is null) + throw new InvalidOperationException("You are not a member of this guild."); + + var permissions = member.Roles.Aggregate((Permissions)0UL, (current, role) => current | (Permissions)ulong.Parse(role.Permissions)); + + if (member.CommunicationDisabledUntil is not null && member.CommunicationDisabledUntil > DateTime.UtcNow) { + permissions &= Permissions.ViewChannel | Permissions.ReadMessageHistory; + } + + if (!permissions.HasFlag(permission)) + throw new PermissionException(Enum.GetValues().Where(p => !permissions.HasFlag(p) && permission.HasFlag(p))); + } +} + +public class PermissionException : Exception { + public IEnumerable MissingPermissions { get; } + + public PermissionException(IEnumerable missingPermissions) : base( + $"You do not have the required permissions to perform this action: {string.Join(", ", missingPermissions)}") { + MissingPermissions = missingPermissions; + } +} \ No newline at end of file