From 39c5401cdb330bd7317cfc547802bcc95ebef4ce Mon Sep 17 00:00:00 2001 From: JacobTech Date: Sun, 21 May 2023 16:14:24 -0400 Subject: [PATCH] Permission Check System Added a system for code to easily check for permission to a given channel. --- LuskiServer/Classes/Luski.cs | 109 +++++++++++++++++- LuskiServer/Classes/TableDef/Categories.cs | 1 + LuskiServer/Classes/TableDef/Channels.cs | 1 + .../Classes/TableDef/UserRoleOverides.cs | 1 - .../Classes/v1/Incoming/ClientSendMessage.cs | 11 ++ .../v1/SocketBulkMessageController.cs | 4 +- .../Controllers/v1/SocketMessageController.cs | 7 +- LuskiServer/Program.cs | 1 + 8 files changed, 125 insertions(+), 10 deletions(-) diff --git a/LuskiServer/Classes/Luski.cs b/LuskiServer/Classes/Luski.cs index 478f284..8b55cdd 100644 --- a/LuskiServer/Classes/Luski.cs +++ b/LuskiServer/Classes/Luski.cs @@ -1,7 +1,7 @@ using System.Security.Cryptography; -using System.Text; using System.Text.Json; using System.Text.Json.Serialization.Metadata; +using LuskiServer.Classes.TableDef; using LuskiServer.Enums; using ServerDatabase; @@ -11,7 +11,7 @@ public static class Luski { public static Database Database = null!; - public static TResult GetSettings(string path, JsonTypeInfo TypeInfo, bool EndOnError = false) where TResult : new() + public static TResult GetSettings(string path, JsonTypeInfo TypeInfo, bool EndOnError = false, bool UpdateOldFile = true) where TResult : new() { TResult? @out; if (!File.Exists(path)) @@ -53,7 +53,7 @@ public static class Luski try { - File.WriteAllText(path, JsonSerializer.Serialize(@out, TypeInfo)); + if (UpdateOldFile) File.WriteAllText(path, JsonSerializer.Serialize(@out, TypeInfo)); } catch (Exception e) { @@ -64,6 +64,109 @@ public static class Luski } public static AppConfig Config = null!; + +public static bool HasAccessToChannel(long User, long Channel, params ServerPermissions[] RequiredPerms) +{ + long[] UserRoleIDList = Tables.Users.Read(Users.Roles, Users.ID.CreateParameter(User)); + List pp = RequiredPerms.ToList(); + if (!pp.Contains(ServerPermissions.ViewChannels)) pp.Add(ServerPermissions.ViewChannels); + List GoodPerms = new(); + bool more = false; + bool CheckCatPerm(long Cat, List NeededPerms, bool more2 = false) + { + more = more2; + if (more2 && pp.Contains(ServerPermissions.ViewCategories)) pp.Add(ServerPermissions.ViewCategories); + long Parent = Tables.Categories.Read(Categories.Parent, Categories.ID.CreateParameter(Channel)); + if (Parent != -1 && !CheckCatPerm(Parent, pp, true)) return false; + long[] CatUserOverides = Tables.Categories.Read(Categories.UserOverides, Categories.ID.CreateParameter(Cat)); + foreach (long CatUserOveride in CatUserOverides) + { + if (Tables.UserRoleOverides.Read(UserRoleOverides.UserID, UserRoleOverides.ID.CreateParameter(CatUserOveride)) != User) continue; + string[] overrids = Tables.UserRoleOverides.Read(UserRoleOverides.Overides, + UserRoleOverides.ID.CreateParameter(CatUserOveride)); + foreach (string o in overrids) + { + foreach (ServerPermissions p in NeededPerms) + { + if (o.StartsWith($"{p.GetNumberString()}:")) + { + if (o.EndsWith("0")) return false; + else GoodPerms.Add(p); + } + } + } + } + long[] CatRoleOverides = Tables.Categories.Read(Categories.RoleOverides, Categories.ID.CreateParameter(Cat)); + foreach (long CatRoleOveride in CatRoleOverides) + { + if (!UserRoleIDList.Contains(Tables.ServerRoleOverides.Read(ServerRoleOverides.RoleID, ServerRoleOverides.ID.CreateParameter(CatRoleOveride)))) continue; + string[] overrids = Tables.UserRoleOverides.Read(ServerRoleOverides.Overides, + ServerRoleOverides.ID.CreateParameter(CatRoleOveride)); + foreach (string o in overrids) + { + foreach (ServerPermissions p in NeededPerms) + { + if (o.StartsWith($"{p.GetNumberString()}:")) + { + if (o.EndsWith("0")) return false; + else GoodPerms.Add(p); + } + } + } + } + + if (GoodPerms.Count == NeededPerms.Count) return true; + return false; + } + + if (!CheckCatPerm(Tables.Channels.Read(Channels.Parent, Channels.ID.CreateParameter(Channel)), pp)) return false; + if (more && !GoodPerms.Contains(ServerPermissions.ViewCategories)) return false; + + foreach (ServerPermissions v in GoodPerms) + { + pp.Remove(v); + } + GoodPerms.Clear(); + long[] ChanUserOverides = Tables.Channels.Read(Channels.UserOverides, Channels.ID.CreateParameter(Channel)); + foreach (long ChanUserOveride in ChanUserOverides) + { + if (Tables.UserRoleOverides.Read(UserRoleOverides.UserID, UserRoleOverides.ID.CreateParameter(ChanUserOveride)) != User) continue; + string[] overrids = Tables.UserRoleOverides.Read(UserRoleOverides.Overides, + UserRoleOverides.ID.CreateParameter(ChanUserOveride)); + foreach (string o in overrids) + { + foreach (ServerPermissions p in pp) + { + if (o.StartsWith($"{p.GetNumberString()}:")) + { + if (o.EndsWith("0")) return false; + else GoodPerms.Add(p); + } + } + } + } + long[] ChanRoleOverides = Tables.Channels.Read(Channels.RoleOverides, Channels.ID.CreateParameter(Channel)); + foreach (long ChanRoleOveride in ChanRoleOverides) + { + if (!UserRoleIDList.Contains(Tables.ServerRoleOverides.Read(ServerRoleOverides.RoleID, ServerRoleOverides.ID.CreateParameter(ChanRoleOveride)))) continue; + string[] overrids = Tables.UserRoleOverides.Read(ServerRoleOverides.Overides, + ServerRoleOverides.ID.CreateParameter(ChanRoleOveride)); + foreach (string o in overrids) + { + foreach (ServerPermissions p in pp) + { + if (o.StartsWith($"{p.GetNumberString()}:")) + { + if (o.EndsWith("0")) return false; + else GoodPerms.Add(p); + } + } + } + } + + if (GoodPerms.Count == pp.Count) return true; + return false; +} public static class Info { diff --git a/LuskiServer/Classes/TableDef/Categories.cs b/LuskiServer/Classes/TableDef/Categories.cs index 20867c4..e02f116 100644 --- a/LuskiServer/Classes/TableDef/Categories.cs +++ b/LuskiServer/Classes/TableDef/Categories.cs @@ -7,6 +7,7 @@ public static class Categories public static TableColumn ID { get; } = new("id", true); public static TableColumn Name { get; } = new("name") { DefaultValue = "New Category"}; public static TableColumn Description { get; } = new("description") { DefaultValue = "Default Description"}; + public static TableColumn Parent { get; } = new("parent") { DefaultValue = -1 }; public static TableColumn InnerCategories { get; } = new("inner_categories") { DefaultValue = Array.Empty() }; public static TableColumn Channels { get; } = new("channels") { DefaultValue = Array.Empty() }; public static TableColumn RoleOverides { get; } = new("role_overides") { DefaultValue = Array.Empty() }; diff --git a/LuskiServer/Classes/TableDef/Channels.cs b/LuskiServer/Classes/TableDef/Channels.cs index f6a8ad3..123a40b 100644 --- a/LuskiServer/Classes/TableDef/Channels.cs +++ b/LuskiServer/Classes/TableDef/Channels.cs @@ -8,6 +8,7 @@ namespace LuskiServer.Classes.TableDef; public static class Channels { public static TableColumn ID { get; } = new("id", true); + public static TableColumn Parent { get; } = new("parent") { DefaultValue = -1 }; public static TableColumn Type { get; } = new("type"); public static TableColumn Epoch { get; } = new("epoch"); public static TableColumn Name { get; } = new("name") { DefaultValue = Encoding.UTF8.GetBytes("New Channel") }; diff --git a/LuskiServer/Classes/TableDef/UserRoleOverides.cs b/LuskiServer/Classes/TableDef/UserRoleOverides.cs index dd28953..08a6c34 100644 --- a/LuskiServer/Classes/TableDef/UserRoleOverides.cs +++ b/LuskiServer/Classes/TableDef/UserRoleOverides.cs @@ -7,6 +7,5 @@ public static class UserRoleOverides { public static TableColumn ID { get; } = new("id", true); public static TableColumn UserID { get; } = new("user_id"); - public static TableColumn ParentOverideID { get; } = new("parent_overide_id"); public static TableColumn Overides { get; } = new("overides"); } \ No newline at end of file diff --git a/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs b/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs index f95ddcc..b8469bc 100644 --- a/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs +++ b/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using JacobTechEncryption.Enums; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace LuskiServer.Classes.v1.Incoming; @@ -21,4 +22,14 @@ public class ClientSendMessage [JsonRequired] [JsonPropertyName("files")] public long[] Files { get; set; } + [JsonInclude] + [BindRequired] + [JsonRequired] + [JsonPropertyName("encryption")] + public EncryptionType Encryption { get; set; } + [JsonInclude] + [BindRequired] + [JsonRequired] + [JsonPropertyName("encoding")] + public EncoderType Encoding { get; set; } } \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketBulkMessageController.cs b/LuskiServer/Controllers/v1/SocketBulkMessageController.cs index ab4a31f..991970e 100644 --- a/LuskiServer/Controllers/v1/SocketBulkMessageController.cs +++ b/LuskiServer/Controllers/v1/SocketBulkMessageController.cs @@ -26,8 +26,8 @@ public class SocketBulkMessageController : ControllerBase long MessagesToDownload = 50; long Max = 200; if (long.TryParse(channel_id, out long Channel_Id) && !Tables.Channels.TryRead(Channels.ID, out _, Channels.ID.CreateParameter(Channel_Id))) return this.ShowError(ErrorCode.InvalidHeader, "The the channel id you have given the server is not a valed id"); - //This needs to be added but using the new permission system. - //if (!Luski.HasAccessToChannel(ID, Channel_Id)) return this.ShowError(ErrorCode.Forbidden); + if (!Luski.HasAccessToChannel(ID, Channel_Id, ServerPermissions.ReadMessageHistory)) + return this.ResponseToResult(new HTTPResponse() { error = ErrorCode.Forbidden }); if (Request.Headers.ContainsKey("messages")) _ = long.TryParse(Request.Headers["messages"].First(), out MessagesToDownload); if (MessagesToDownload > Max) MessagesToDownload = Max; string? MostRecentID = null; diff --git a/LuskiServer/Controllers/v1/SocketMessageController.cs b/LuskiServer/Controllers/v1/SocketMessageController.cs index 3c17215..6a79be0 100644 --- a/LuskiServer/Controllers/v1/SocketMessageController.cs +++ b/LuskiServer/Controllers/v1/SocketMessageController.cs @@ -23,8 +23,7 @@ public class SocketMessageController : ControllerBase try { if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; - //TODO Add a check system for channel access - //if (Luski.HasAccessToChannel(ID, data.ChannelID)) + if (Luski.HasAccessToChannel(ID, data.ChannelID, ServerPermissions.SendMessages)) { Luski.Snowflake Id = Luski.Snowflake.GenerateSnowflake(Tables.Channels.Read(Channels.Epoch, Channels.ID.CreateParameter(data.ChannelID))); ChannelType type = Tables.Channels.Read(Channels.Type, Channels.ID.CreateParameter(data.ChannelID)); @@ -42,8 +41,8 @@ public class SocketMessageController : ControllerBase Messages.Context.CreateParameter(Convert.FromBase64String(data.Base64Context)), Messages.TimeStamp.CreateParameter(Id.Timestamp), Messages.Files.CreateParameter(data.Files), - Messages.EncoderType.CreateParameter(EncoderType.UTF8), - Messages.EncryptionType.CreateParameter(EncryptionType.RSA)); + Messages.EncoderType.CreateParameter(data.Encoding), + Messages.EncryptionType.CreateParameter(data.Encryption)); //TODO Get all ID for members to send to WSS.SendData(SendType.ID_Group, new ServerEvent() { diff --git a/LuskiServer/Program.cs b/LuskiServer/Program.cs index ccb27d3..f030449 100644 --- a/LuskiServer/Program.cs +++ b/LuskiServer/Program.cs @@ -93,6 +93,7 @@ if (!Tables.Categories.TryRead(Categories.ID, out _, Categories.ID.CreateParamet Tables.Categories.Insert( Categories.ID.CreateParameter(0), Categories.Name.CreateParameter("server"), + Categories.Parent.CreateParameter(-1), Categories.Description.CreateParameter( "The default category for the server. Everybody will see this category."), Categories.RoleOverides.CreateParameter(new long[1] { 0 })