From cd5ab859112a1cbf57103160d64aa0be8500d666 Mon Sep 17 00:00:00 2001 From: JacobTech Date: Sun, 2 Jul 2023 11:41:04 -0400 Subject: [PATCH] Endpoints Madness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I decided to add as many endpoints as needed for basic functionality. The following endpoints were added: • [Delete] /v1/Keys • [Post] /v1/Keys • [Get] /v1/Keys • [Get] /v1/SocketAccount • [Post] /v1/SocketAccount • [Post] /v1/SocketChannel • [Delete] /v1/SocketChannel • [Patch] /v1/SocketChannel • [Get] /v1/SocketChannel • [Get] /v1/SocketFile • [Delete] /v1/SocketFile • [Post] /v1/SocketFile • [Get] /v1/SocketMessage • [Get] /v1/SocketUser --- LuskiServer/Classes/EXT.cs | 85 +++-------- LuskiServer/Classes/HTTPResponse.cs | 3 +- LuskiServer/Classes/Luski.cs | 84 ++++++++++- LuskiServer/Classes/TableDef/Categories.cs | 10 +- LuskiServer/Classes/TableDef/Channels.cs | 11 +- LuskiServer/Classes/TableDef/Files.cs | 8 +- LuskiServer/Classes/TableDef/Keys.cs | 18 +++ LuskiServer/Classes/TableDef/Messages.cs | 2 +- LuskiServer/Classes/TableDef/Sessions.cs | 17 +++ LuskiServer/Classes/TableDef/Users.cs | 8 +- LuskiServer/Classes/Tables.cs | 22 +-- .../WebTypes/BasePermOverideRequest.cs | 6 + .../Classes/WebTypes/ClientKeyPostReqest.cs | 9 ++ LuskiServer/Classes/WebTypes/File.cs | 4 +- .../Classes/WebTypes/SocketBulkMessage.cs | 4 +- LuskiServer/Classes/WebTypes/SocketMessage.cs | 5 +- .../Classes/WebTypes/UserChannelRequest.cs | 24 ++++ .../Classes/WebTypes/UserKeyGetRequest.cs | 12 ++ .../WebTypes/UserPermOverideRequest.cs | 8 ++ .../WebTypes/UserRoleOverideRequest.cs | 8 ++ .../Classes/v1/Incoming/ClientSendMessage.cs | 4 +- LuskiServer/Classes/v1/OutGoing/ServerFile.cs | 8 ++ .../Classes/v1/OutGoing/UserResponse.cs | 14 ++ LuskiServer/Controllers/v1/KeysController.cs | 123 ++++++++++++++-- ...ntroller.cs => SocketAccountController.cs} | 136 +++++++++++++++--- .../v1/SocketBulkMessageController.cs | 13 +- .../Controllers/v1/SocketChannelController.cs | 134 +++++++++++++++++ .../Controllers/v1/SocketFileController.cs | 94 ++++++++++++ .../Controllers/v1/SocketMessageController.cs | 67 ++++++++- .../Controllers/v1/SocketUserController.cs | 37 +++++ LuskiServer/Enums/ServerPermissions.cs | 13 +- LuskiServer/Interfaces/IWebResponse.cs | 6 + LuskiServer/LuskiServer.csproj | 4 +- LuskiServer/Program.cs | 33 +++-- LuskiServer/Properties/launchSettings.json | 4 +- 35 files changed, 864 insertions(+), 174 deletions(-) create mode 100644 LuskiServer/Classes/TableDef/Keys.cs create mode 100644 LuskiServer/Classes/TableDef/Sessions.cs create mode 100644 LuskiServer/Classes/WebTypes/BasePermOverideRequest.cs create mode 100644 LuskiServer/Classes/WebTypes/ClientKeyPostReqest.cs create mode 100644 LuskiServer/Classes/WebTypes/UserChannelRequest.cs create mode 100644 LuskiServer/Classes/WebTypes/UserKeyGetRequest.cs create mode 100644 LuskiServer/Classes/WebTypes/UserPermOverideRequest.cs create mode 100644 LuskiServer/Classes/WebTypes/UserRoleOverideRequest.cs create mode 100644 LuskiServer/Classes/v1/OutGoing/ServerFile.cs create mode 100644 LuskiServer/Classes/v1/OutGoing/UserResponse.cs rename LuskiServer/Controllers/v1/{CreateAccountController.cs => SocketAccountController.cs} (51%) create mode 100644 LuskiServer/Controllers/v1/SocketChannelController.cs create mode 100644 LuskiServer/Controllers/v1/SocketFileController.cs create mode 100644 LuskiServer/Controllers/v1/SocketUserController.cs create mode 100644 LuskiServer/Interfaces/IWebResponse.cs diff --git a/LuskiServer/Classes/EXT.cs b/LuskiServer/Classes/EXT.cs index 403fa30..9c0cb0c 100644 --- a/LuskiServer/Classes/EXT.cs +++ b/LuskiServer/Classes/EXT.cs @@ -1,5 +1,3 @@ -using System.Diagnostics; -using System.Net.Mime; using System.Text; using LuskiServer.Classes.TableDef; using LuskiServer.Enums; @@ -9,20 +7,7 @@ using Microsoft.AspNetCore.Mvc; namespace LuskiServer.Classes; public static class EXT -{/* - public static bool CanTokenRequest(this ControllerBase Base, out long id, out TResult? result) where TResult : HTTPResponse, new() - { - if (Base.Request.Headers.ContainsKey("token")) - { - return ValidateToke(Base, out id, out result); - } - result = Base.ShowError(ErrorCode.MissingToken); - id = 0; - return false; - } - */ - - +{ public static string GetNumberString(this ServerPermissions enu) { return ((long)(enu)).ToString(); @@ -44,82 +29,46 @@ public static class EXT if (LogInDB) { Tables.Logs.Insert( - Logs.ID.CreateParameter(Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch) .ID), + Logs.ID.CreateParameter(Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch).ID), Logs.Type.CreateParameter(LogType.Error), Logs.Message.CreateParameter(Error.ToString())); } return Base.ShowError(ErrorCode.ServerError, Error.Message); } + + public static IActionResult ResponseCodeToResult(this ControllerBase Base, ErrorCode Result, string msg = "") + { + return Base.ResponseToResult( + new HTTPResponse() + { + error = Result, + error_message = msg + }); + } - public static IActionResult ResponseToResult(this ControllerBase Base, TResult Result) where TResult : HTTPResponse + public static IActionResult ResponseToResult(this ControllerBase Base, TResult Result) where TResult : IWebResponse { return Base.StatusCode(StatusCodes.Status200OK, Result); } public static IActionResult ShowError(this ControllerBase Base, ErrorCode code, string Error) { - return Base.StatusCode(403, new HTTPResponse() + int cod = 403; + if (code == ErrorCode.ServerError) cod = StatusCodes.Status500InternalServerError; + return Base.StatusCode(cod, new HTTPResponse() { error = code, error_message = Error }); } - /* - public static TReturn ShowError(this ControllerBase Base, ErrorCode code, Exception? Error, bool LogInDB = true) where TReturn : HTTPResponse, new() - { - if (Error is null) return new TReturn() - { - error = ErrorCode.ServerError, - error_message = "Something Went wrong in the error handler." - }; - try - { - StackTrace st = new(Error, true); - StackFrame? frame = st.GetFrame(0); - string? controler = Base.RouteData.Values["controller"]?.ToString(); - string Line = "'Unknown'"; - if (frame is not null) Line = frame.GetFileLineNumber().ToString(); - string msg = $"In '{controler}Controller.cs' on line '{Line}' through error '{Error.Message}' and ST'{st}' and ERROR:\n'{Error}' FRAM:\n '{frame}'"; - //if (LogInDB) Log(msg, LogType.Error); - return Base.ShowError(code, Error.Message); - } - catch (Exception ex) - { - Console.WriteLine(ex); - return new TReturn() - { - error = ErrorCode.ServerError, - error_message = "Something Went wrong in the error handler" - }; - - } - } - - public static TReturn ShowError(this ControllerBase Base, ErrorCode code, string? Error = null) where TReturn : HTTPResponse, new() - { - Base.Response.ContentType = "application/json"; - switch (code) - { - case ErrorCode.Forbidden or ErrorCode.InvalidHeader or ErrorCode.InvalidToken or ErrorCode.MissingToken or ErrorCode.MissingToken or ErrorCode.MissingHeader: - Base.Response.StatusCode = StatusCodes.Status403Forbidden; - break; - } - TReturn hTTPResponse = new() - { - error = code, - error_message = Error - }; - return hTTPResponse; - } - */ private static bool CheckToken(string Token, ref long ID) { try { string id = Encoding.UTF8.GetString(Convert.FromBase64String(Token.Split('.')[0])); - string? tok = Tables.Users.Read(Users.Token, Users.ID.CreateParameter(long.Parse(id))); + string? tok = Tables.Sessions.Read(Sessions.Token, Sessions.ID.CreateParameter(long.Parse(id))); if (!string.IsNullOrWhiteSpace(tok) && tok == Token) { ID = long.Parse(id); diff --git a/LuskiServer/Classes/HTTPResponse.cs b/LuskiServer/Classes/HTTPResponse.cs index 5c993b8..90f4d93 100644 --- a/LuskiServer/Classes/HTTPResponse.cs +++ b/LuskiServer/Classes/HTTPResponse.cs @@ -1,9 +1,10 @@ using System.Text.Json.Serialization; using LuskiServer.Enums; +using LuskiServer.Interfaces; namespace LuskiServer.Classes; -public class HTTPResponse +public class HTTPResponse : IWebResponse { public ErrorCode? error { get; set; } = default!; public string? error_message { get; set; } = default!; diff --git a/LuskiServer/Classes/Luski.cs b/LuskiServer/Classes/Luski.cs index 0f383d3..20aa4a7 100644 --- a/LuskiServer/Classes/Luski.cs +++ b/LuskiServer/Classes/Luski.cs @@ -164,6 +164,78 @@ public static class Luski dbConnection.Close(); return Members.ToArray(); } + + public static bool HasPermissions(long User, params ServerPermissions[] RequiredPerms) + { + long[] UserRoleIDList = Tables.Users.Read(Users.Roles, Users.ID.CreateParameter(User)); + List GoodPerms = new(); + foreach (long RoleID in UserRoleIDList) + { + List pers = Tables.Roles.Read(Roles.ServerPermissions, Roles.ID.CreateParameter(RoleID)).ToList(); + foreach (ServerPermissions rp in RequiredPerms) + { + if (!GoodPerms.Contains(rp) && pers.Contains(rp)) GoodPerms.Add(rp); + } + } + + return (GoodPerms.Count == RequiredPerms.Length); + } + + public static bool HasAccessToCategory(long User, long Category, params ServerPermissions[] RequiredPerms) + { + long[] UserRoleIDList = Tables.Users.Read(Users.Roles, Users.ID.CreateParameter(User)); + List pp = RequiredPerms.ToList(); + if (!pp.Contains(ServerPermissions.ViewCategories)) pp.Add(ServerPermissions.ViewCategories); + List GoodPerms = new(); + long[] CatUserOverides = Tables.Categories.Read(Categories.UserOverides, Categories.ID.CreateParameter(Category)); + 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 pp) + { + 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(Category)); + 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 pp) + { + if (o.StartsWith($"{p.GetNumberString()}:")) + { + if (o.EndsWith("0")) return false; + else GoodPerms.Add(p); + } + } + } + } + + foreach (long RoleID in UserRoleIDList) + { + List pers = Tables.Roles.Read(Roles.ServerPermissions, Roles.ID.CreateParameter(RoleID)).ToList(); + foreach (ServerPermissions rp in pp) + { + if (!GoodPerms.Contains(rp) && pers.Contains(rp)) GoodPerms.Add(rp); + } + } + + if (GoodPerms.Count == pp.Count) return true; + return false; + } public static bool HasAccessToChannel(long User, long Channel, params ServerPermissions[] RequiredPerms) { @@ -209,8 +281,16 @@ public static class Luski } } - if (GoodPerms.Count == pp.Count) return true; - return false; + foreach (long RoleID in UserRoleIDList) + { + List pers = Tables.Roles.Read(Roles.ServerPermissions, Roles.ID.CreateParameter(RoleID)).ToList(); + foreach (ServerPermissions rp in pp) + { + if (!GoodPerms.Contains(rp) && pers.Contains(rp)) GoodPerms.Add(rp); + } + } + + return GoodPerms.Count == pp.Count; } public static class Info diff --git a/LuskiServer/Classes/TableDef/Categories.cs b/LuskiServer/Classes/TableDef/Categories.cs index a28482f..7a22fe7 100644 --- a/LuskiServer/Classes/TableDef/Categories.cs +++ b/LuskiServer/Classes/TableDef/Categories.cs @@ -1,3 +1,5 @@ +using System.Text; +using JacobTechEncryption.Enums; using ServerDatabase; using ServerDatabase.SourceGenerator; @@ -6,13 +8,17 @@ namespace LuskiServer.Classes.TableDef; 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 Name { get; } = new("name") { DefaultValue = Encoding.UTF8.GetBytes("New Category") }; + public static TableColumn Description { get; } = new("description") { DefaultValue = Encoding.UTF8.GetBytes("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() }; public static TableColumn UserOverides { get; } = new("member_overides") { DefaultValue = Array.Empty() }; + public static TableColumn TitleEncryptionKey { get; } = new("title_encryption_key") { DefaultValue = 0 }; + public static TableColumn DescriptionEncryptionKey { get; } = new("description_encryption_key") { DefaultValue = 0 }; + public static TableColumn TitleEncoderType { get; } = new("title_encoder_type") { DefaultValue = EncoderType.UTF8 }; + public static TableColumn DescriptionEncoderType { get; } = new("description_encoder_type") { DefaultValue = EncoderType.UTF8 }; } [TableRow(typeof(Categories))] public partial class CategoryRow diff --git a/LuskiServer/Classes/TableDef/Channels.cs b/LuskiServer/Classes/TableDef/Channels.cs index 990fe06..6b72685 100644 --- a/LuskiServer/Classes/TableDef/Channels.cs +++ b/LuskiServer/Classes/TableDef/Channels.cs @@ -14,15 +14,16 @@ public static class Channels public static TableColumn Epoch { get; } = new("epoch"); public static TableColumn Name { get; } = new("name") { DefaultValue = Encoding.UTF8.GetBytes("New Channel") }; public static TableColumn Description { get; } = new("description") { DefaultValue = Encoding.UTF8.GetBytes("New Channel") }; - public static TableColumn Key { get; } = new("key") { DefaultValue = string.Empty }; public static TableColumn RoleOverides { get; } = new("role_overides") { DefaultValue = Array.Empty() }; public static TableColumn UserOverides { get; } = new("member_overides") { DefaultValue = Array.Empty() }; - public static TableColumn TitleEncryptionType { get; } = new("title_encryption_type") { DefaultValue = EncryptionType.None }; - public static TableColumn DescriptionEncryptionType { get; } = new("description_encryption_type") { DefaultValue = EncryptionType.None }; - public static TableColumn AllowedEncryptionTypes { get; } = new("allowed_encryption_types") { DefaultValue = new [] { EncryptionType.RSA } }; + public static TableColumn TitleEncryptionKey { get; } = new("title_encryption_key") { DefaultValue = 0 }; + public static TableColumn DescriptionEncryptionKey { get; } = new("description_encryption_key") { DefaultValue = 0 }; + public static TableColumn EncoderBlacklist { get; } = new("encoder_blacklist") { DefaultValue = false }; + public static TableColumn EncryptionBlacklist { get; } = new("encryption_blacklist") { DefaultValue = false }; + public static TableColumn EncryptionTypes { get; } = new("encryption_types") { DefaultValue = new [] { EncryptionType.RSA } }; public static TableColumn TitleEncoderType { get; } = new("title_encoder_type") { DefaultValue = EncoderType.UTF8 }; public static TableColumn DescriptionEncoderType { get; } = new("description_encoder_type") { DefaultValue = EncoderType.UTF8 }; - public static TableColumn AllowedEncoderTypes { get; } = new("allowed_encoder_types") { DefaultValue = new [] + public static TableColumn EncoderTypes { get; } = new("encoder_types") { DefaultValue = new [] { EncoderType.UTF8, EncoderType.UTF16, EncoderType.UTF32, EncoderType.ASCII, diff --git a/LuskiServer/Classes/TableDef/Files.cs b/LuskiServer/Classes/TableDef/Files.cs index 21c48bf..8a90003 100644 --- a/LuskiServer/Classes/TableDef/Files.cs +++ b/LuskiServer/Classes/TableDef/Files.cs @@ -7,14 +7,16 @@ namespace LuskiServer.Classes.TableDef; public static class Files { public static TableColumn ID { get; } = new("id", true); - public static TableColumn ChannelID { get; } = new("channel_id"); + public static TableColumn Owner { get; } = new("owner"); + public static TableColumn Public { get; } = new("public_download"); + public static TableColumn AllowedChannels { get; } = new("channels"); public static TableColumn Size { get; } = new("size"); public static TableColumn Name { get; } = new("name"); public static TableColumn Hash { get; } = new("hash"); public static TableColumn Data { get; } = new("data"); - public static TableColumn EncryptionType { get; } = new("encryption_type"); + public static TableColumn EncryptionKey { get; } = new("encryption_key"); public static TableColumn EncoderType { get; } = new("encoder_type"); - public static TableColumn NameEncryptionType { get; } = new("name_encryption_type"); + public static TableColumn NameEncryptionKey { get; } = new("name_encryption_key"); public static TableColumn NameEncoderType { get; } = new("name_encoder_type"); } diff --git a/LuskiServer/Classes/TableDef/Keys.cs b/LuskiServer/Classes/TableDef/Keys.cs new file mode 100644 index 0000000..b7eab03 --- /dev/null +++ b/LuskiServer/Classes/TableDef/Keys.cs @@ -0,0 +1,18 @@ +using JacobTechEncryption.Enums; +using ServerDatabase; +using ServerDatabase.SourceGenerator; + +namespace LuskiServer.Classes.TableDef; + +public static class Keys +{ + public static TableColumn ID { get; } = new("id", true); + public static TableColumn Owner { get; } = new("owner"); + public static TableColumn EncryptionType { get; } = new("encryption_type"); + public static TableColumn KeyData { get; } = new("key_data"); +} + +[TableRow(typeof(Keys))] +public partial class KeyRow +{ +} \ No newline at end of file diff --git a/LuskiServer/Classes/TableDef/Messages.cs b/LuskiServer/Classes/TableDef/Messages.cs index 9c14e58..75839ed 100644 --- a/LuskiServer/Classes/TableDef/Messages.cs +++ b/LuskiServer/Classes/TableDef/Messages.cs @@ -11,7 +11,7 @@ public static class Messages public static TableColumn AuthorID { get; } = new("author_id"); public static TableColumn TimeStamp { get; } = new("ts"); public static TableColumn Context { get; } = new("context"); - public static TableColumn EncryptionType { get; } = new("encryption_type"); + public static TableColumn EncryptionKey { get; } = new("encryption_key"); public static TableColumn EncoderType { get; } = new("encoder_type"); public static TableColumn Files { get; } = new("files"); } diff --git a/LuskiServer/Classes/TableDef/Sessions.cs b/LuskiServer/Classes/TableDef/Sessions.cs new file mode 100644 index 0000000..6dc3c9c --- /dev/null +++ b/LuskiServer/Classes/TableDef/Sessions.cs @@ -0,0 +1,17 @@ +using ServerDatabase; +using ServerDatabase.SourceGenerator; + +namespace LuskiServer.Classes.TableDef; + +public static class Sessions +{ + public static TableColumn ID { get; } = new("id", true); + public static TableColumn User { get; } = new("user"); + public static TableColumn WSSTCP { get; } = new("wsstcp"); + public static TableColumn Token { get; } = new("token"); + public static TableColumn LoginToken { get; } = new("login_token"); + public static TableColumn SessionKey { get; } = new("session_key"); +} +[TableRow(typeof(Sessions))] +public partial class SessionsRow +{} diff --git a/LuskiServer/Classes/TableDef/Users.cs b/LuskiServer/Classes/TableDef/Users.cs index 716d3d0..5ba14a6 100644 --- a/LuskiServer/Classes/TableDef/Users.cs +++ b/LuskiServer/Classes/TableDef/Users.cs @@ -16,12 +16,8 @@ public class Users public static TableColumn Username { get; } = new("username"); public static TableColumn Password { get; } = new("password"); public static TableColumn Salt { get; } = new("salt"); - public static TableColumn LoginToken { get; } = new("login_token"); - public static TableColumn SessionKey { get; } = new("session_key"); - public static TableColumn WSSTCP { get; } = new("wsstcp"); - public static TableColumn Token { get; } = new("token"); - public static TableColumn OfflineData { get; } = new("offline_data"); - public static TableColumn OffileKey { get; } = new("offline_key") {DefaultValue = string.Empty}; + public static TableColumn OfflineData { get; } = new("offline_data"); + public static TableColumn OffileKey { get; } = new("offline_key"); } [TableRow(typeof(Users))] diff --git a/LuskiServer/Classes/Tables.cs b/LuskiServer/Classes/Tables.cs index 357a1a5..c6bf934 100644 --- a/LuskiServer/Classes/Tables.cs +++ b/LuskiServer/Classes/Tables.cs @@ -5,14 +5,16 @@ namespace LuskiServer.Classes; public static class Tables { - public static Table Users { get; } = new Table("users", null!); - public static Table Roles { get; } = new Table("roles", null!); - public static Table Logs { get; } = new Table("logs", null!); - public static Table Files { get; } = new Table("files", null!); - public static Table Categories { get; } = new Table("categories", null!); - public static Table Channels { get; } = new Table("channels", null!); - public static Table Messages { get; } = new Table("messages", null!); - public static Table ServerRoleOverides { get; } = new Table("role_overides", null!); - public static Table UserRoleOverides { get; } = new Table("user_overides", null!); - public static Table SessionTokens { get; } = new Table("session_tokens", null!); + public static Table Users { get; } = new("users", null!); + public static Table Roles { get; } = new("roles", null!); + public static Table Logs { get; } = new("logs", null!); + public static Table Files { get; } = new("files", null!); + public static Table Categories { get; } = new("categories", null!); + public static Table Channels { get; } = new("channels", null!); + public static Table Messages { get; } = new("messages", null!); + public static Table ServerRoleOverides { get; } = new("role_overides", null!); + public static Table UserRoleOverides { get; } = new("user_overides", null!); + public static Table Sessions { get; } = new("sessions", null!); + public static Table SessionTokens { get; } = new("session_tokens", null!); + public static Table Keys { get; } = new("keys", null!); } \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/BasePermOverideRequest.cs b/LuskiServer/Classes/WebTypes/BasePermOverideRequest.cs new file mode 100644 index 0000000..5312588 --- /dev/null +++ b/LuskiServer/Classes/WebTypes/BasePermOverideRequest.cs @@ -0,0 +1,6 @@ +namespace LuskiServer.Classes.WebTypes; + +public class BasePermOverideRequest +{ + +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/ClientKeyPostReqest.cs b/LuskiServer/Classes/WebTypes/ClientKeyPostReqest.cs new file mode 100644 index 0000000..5380f51 --- /dev/null +++ b/LuskiServer/Classes/WebTypes/ClientKeyPostReqest.cs @@ -0,0 +1,9 @@ +using JacobTechEncryption.Enums; + +namespace LuskiServer.Classes.WebTypes; + +public class ClientKeyPostReqest +{ + public EncryptionType encryption_type { get; set; } + public string key_data { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/File.cs b/LuskiServer/Classes/WebTypes/File.cs index 7c9643f..95b5797 100644 --- a/LuskiServer/Classes/WebTypes/File.cs +++ b/LuskiServer/Classes/WebTypes/File.cs @@ -9,8 +9,8 @@ public class File public string name { get; set; } = default!; public EncoderType encoder_type { get; set; } = default!; public EncoderType name_encoder_type { get; set; } = default!; - public EncryptionType encryption_type { get; set; } = default!; - public EncryptionType name_encryption_type { get; set; } = default!; + public long encryption_key { get; set; } = default!; + public long name_encryption_key { get; set; } = default!; public string[] data { get; set; } = default!; public ulong? size { get; set; } = default!; public long? id { get; set; } = default!; diff --git a/LuskiServer/Classes/WebTypes/SocketBulkMessage.cs b/LuskiServer/Classes/WebTypes/SocketBulkMessage.cs index 818377b..2696f9f 100644 --- a/LuskiServer/Classes/WebTypes/SocketBulkMessage.cs +++ b/LuskiServer/Classes/WebTypes/SocketBulkMessage.cs @@ -1,6 +1,8 @@ +using LuskiServer.Interfaces; + namespace LuskiServer.Classes.WebTypes; -public class SocketBulkMessage : HTTPResponse +public class SocketBulkMessage : IWebResponse { public SocketMessage[] messages { get; set; } = default!; } \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/SocketMessage.cs b/LuskiServer/Classes/WebTypes/SocketMessage.cs index 268f199..6ad0f30 100644 --- a/LuskiServer/Classes/WebTypes/SocketMessage.cs +++ b/LuskiServer/Classes/WebTypes/SocketMessage.cs @@ -1,14 +1,15 @@ using JacobTechEncryption.Enums; +using LuskiServer.Interfaces; namespace LuskiServer.Classes.WebTypes; -public class SocketMessage : HTTPResponse +public class SocketMessage : IWebResponse { public long channel_id { get; set; } = default!; public long user_id { get; set; } = default!; public long id { get; set; } = default!; public string content { get; set; } = default!; - public EncryptionType encryption_type { get; set; } = default!; + public long encryption_key { get; set; } = default!; public EncoderType encoder_type { get; set; } = default!; public File[] files { get; set; } = default!; } \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/UserChannelRequest.cs b/LuskiServer/Classes/WebTypes/UserChannelRequest.cs new file mode 100644 index 0000000..74aa1a2 --- /dev/null +++ b/LuskiServer/Classes/WebTypes/UserChannelRequest.cs @@ -0,0 +1,24 @@ +using JacobTechEncryption.Enums; +using LuskiServer.Enums; +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.WebTypes; + +public class UserChannelRequest : IWebResponse +{ + public long id { get; set; } + public long parent { get; set; } + public ChannelType type { get; set; } + public string name { get; set; } + public string description { get; set; } + public UserRoleOverideRequest[] role_overides { get; set; } + public UserPermOverideRequest[] user_overides { get; set; } + public long title_encryption_key { get; set; } + public long description_encryption_key { get; set; } + public bool encoder_blacklist { get; set; } + public bool encryption_blacklist { get; set; } + public EncryptionType[] encryption_types { get; set; } + public EncoderType title_encoder_type { get; set; } + public EncoderType description_encoder_type { get; set; } + public EncoderType[] encoder_types { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/UserKeyGetRequest.cs b/LuskiServer/Classes/WebTypes/UserKeyGetRequest.cs new file mode 100644 index 0000000..f191953 --- /dev/null +++ b/LuskiServer/Classes/WebTypes/UserKeyGetRequest.cs @@ -0,0 +1,12 @@ +using JacobTechEncryption.Enums; +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.WebTypes; + +public class UserKeyGetRequest : IWebResponse +{ + public long id { get; set; } + public long owner { get; set; } + public EncryptionType encryption_type { get; set; } + public string key_data { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/UserPermOverideRequest.cs b/LuskiServer/Classes/WebTypes/UserPermOverideRequest.cs new file mode 100644 index 0000000..5ed84db --- /dev/null +++ b/LuskiServer/Classes/WebTypes/UserPermOverideRequest.cs @@ -0,0 +1,8 @@ +namespace LuskiServer.Classes.WebTypes; + +public class UserPermOverideRequest : HTTPResponse +{ + public long id { get; set; } + public long user_id { get; set; } + public string[] overides { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/UserRoleOverideRequest.cs b/LuskiServer/Classes/WebTypes/UserRoleOverideRequest.cs new file mode 100644 index 0000000..0a41976 --- /dev/null +++ b/LuskiServer/Classes/WebTypes/UserRoleOverideRequest.cs @@ -0,0 +1,8 @@ +namespace LuskiServer.Classes.WebTypes; + +public class UserRoleOverideRequest : HTTPResponse +{ + public long id { get; set; } + public long role_id { get; set; } + public string[] overides { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs b/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs index b8469bc..78b95a4 100644 --- a/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs +++ b/LuskiServer/Classes/v1/Incoming/ClientSendMessage.cs @@ -25,8 +25,8 @@ public class ClientSendMessage [JsonInclude] [BindRequired] [JsonRequired] - [JsonPropertyName("encryption")] - public EncryptionType Encryption { get; set; } + [JsonPropertyName("encryption_key")] + public long EncryptionKey { get; set; } [JsonInclude] [BindRequired] [JsonRequired] diff --git a/LuskiServer/Classes/v1/OutGoing/ServerFile.cs b/LuskiServer/Classes/v1/OutGoing/ServerFile.cs new file mode 100644 index 0000000..9e91d6d --- /dev/null +++ b/LuskiServer/Classes/v1/OutGoing/ServerFile.cs @@ -0,0 +1,8 @@ +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.v1.OutGoing; + +public class ServerFile : IWebResponse +{ + public long id { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/v1/OutGoing/UserResponse.cs b/LuskiServer/Classes/v1/OutGoing/UserResponse.cs new file mode 100644 index 0000000..60415fe --- /dev/null +++ b/LuskiServer/Classes/v1/OutGoing/UserResponse.cs @@ -0,0 +1,14 @@ +using LuskiServer.Enums; +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.v1.OutGoing; + +public class UserResponse : IWebResponse +{ + public Status status { get; set; } = default!; + public long[] roles { get; set; } = default!; + public long id { get; set; } = default!; + public string displayname { get; set; } = default!; + public PictureType picture_type { get; set; } = default!; + public long selected_channel { get; set; } = default!; +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/KeysController.cs b/LuskiServer/Controllers/v1/KeysController.cs index 3a4b437..061692c 100644 --- a/LuskiServer/Controllers/v1/KeysController.cs +++ b/LuskiServer/Controllers/v1/KeysController.cs @@ -5,11 +5,15 @@ using JacobTechEncryption; using JacobTechEncryption.Enums; using LuskiServer.Classes; using LuskiServer.Classes.TableDef; +using LuskiServer.Classes.WebTypes; using LuskiServer.Enums; using Microsoft.AspNetCore.Mvc; namespace LuskiServer.Controllers.v1; +/// +/// This controller is for handing all request relating to encryption keys. +/// [ApiVersion(1)] [ApiController] public class KeysController : ControllerBase @@ -26,39 +30,128 @@ public class KeysController : ControllerBase { return File(Encoding.UTF8.GetBytes(Luski.Encryption.Keys.PublicKey), "application/xml"); } + + /// + /// Make a delete request to this endpoint to delete a key from the server. + /// + /// Your Luski token for the server. + /// The public key id you want to delete on the server. + /// + [HttpDelete] + [Produces(MediaTypeNames.Application.Json)] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Delete([FromHeader(Name = "id")]long keyid, [FromHeader(Name = "token")]string? token) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Keys.TryRead(Keys.Owner, out long Owner, Keys.ID.CreateParameter(keyid)) || (Owner != ID || !Luski.HasPermissions(ID, ServerPermissions.DeleteKeys))) + return this.ResponseCodeToResult(ErrorCode.Forbidden); + + Tables.Keys.DeleteRow(Keys.ID.CreateParameter(keyid)); + return StatusCode(202); + } + catch (Exception ex) + { + return this.ShowError(ex); + } + } + + /// + /// Make a post request to this URL to add a new key to the server. + /// + /// Your Luski token for the server + /// The public key info you want to store on the server + /// + [HttpPost] + [Consumes(typeof(ClientKeyPostReqest), MediaTypeNames.Application.Json)] + [Produces(MediaTypeNames.Application.Json)] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Post([FromBody]ClientKeyPostReqest keyreq, [FromHeader(Name = "token")]string? token) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + + Luski.Snowflake sf = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + Tables.Keys.Insert( + Keys.ID.CreateParameter(sf.ID), + Keys.Owner.CreateParameter(ID), + Keys.EncryptionType.CreateParameter(keyreq.encryption_type), + Keys.KeyData.CreateParameter(Convert.FromBase64String(keyreq.key_data))); + return StatusCode(202); + } + catch (Exception ex) + { + return this.ShowError(ex); + } + } + + /// + /// Make a get request to this endpont to get a public key from the server. + /// + /// The public key id you want to get from the server. + [HttpGet] + [Produces(MediaTypeNames.Application.Json)] + [ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "id")]long keyid) + { + try + { + if (!Tables.Keys.TryReadRow(out KeyRow Row, Keys.ID.CreateParameter(keyid))) return this.ResponseCodeToResult(ErrorCode.Forbidden); + return this.ResponseToResult(new UserKeyGetRequest() + { + id = Row.ID, + owner = Row.Owner, + encryption_type = Row.EncryptionType, + key_data = Convert.ToBase64String(Row.KeyData) + }); + } + catch (Exception ex) + { + return this.ShowError(ex); + } + } /// /// Make a post request to this URL to set you offline data key. /// - /// Your Luski token for the server - /// The key you want to set for when you go offline + /// Your Luski token for the server. + /// The key you want to set for when you go offline. /// [HttpPost] - [Consumes(MediaTypeNames.Application.Xml)] + [Consumes(typeof(ClientKeyPostReqest), MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status202Accepted)] [ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)] + [ProducesResponseType(typeof(HTTPResponse), 500)] [Route(Luski.Info.Routes.Default.Base + "/SetOfflineKey")] - public IActionResult SetOfflineKey([FromBody]byte[]? keyy, [FromHeader(Name = "token")]string? token) + public IActionResult SetOfflineKey([FromBody]ClientKeyPostReqest keyreq, [FromHeader(Name = "token")]string? token) { try { string key = ""; if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; - string[]? data = Tables.Users.Read(Users.OfflineData, Users.ID.CreateParameter(ID)); - if (data is not null) return this.ShowError(ErrorCode.Forbidden, "you cant change your key untill you download your data"); - - try + byte[][]? data = Tables.Users.Read(Users.OfflineData, Users.ID.CreateParameter(ID)); + if (data is not null && data.Any()) return this.ShowError(ErrorCode.Forbidden, "you cant change your key untill you download your data"); + long k = 0; + if ((k = Tables.Users.Read(Users.OffileKey, Users.ID.CreateParameter(ID))) != 0) { - byte[] g = Encryption.RSA.Encrypt("Test data to send to client", key, EncoderType.UTF8); - } - catch - { - - return this.ShowError(ErrorCode.InvalidPostData, "The key you sent the server appears to be incorect"); + Tables.Keys.DeleteRow(Keys.ID.CreateParameter(k)); } + Luski.Snowflake sf = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + Tables.Keys.Insert( + Keys.ID.CreateParameter(sf.ID), + Keys.Owner.CreateParameter(ID), + Keys.EncryptionType.CreateParameter(keyreq.encryption_type), + Keys.KeyData.CreateParameter(Convert.FromBase64String(keyreq.key_data))); Tables.Users.Update(Users.ID, ID, - Users.OffileKey.CreateParameter(key)); + Users.OffileKey.CreateParameter(sf.ID)); return StatusCode(202); } catch (Exception ex) diff --git a/LuskiServer/Controllers/v1/CreateAccountController.cs b/LuskiServer/Controllers/v1/SocketAccountController.cs similarity index 51% rename from LuskiServer/Controllers/v1/CreateAccountController.cs rename to LuskiServer/Controllers/v1/SocketAccountController.cs index 5daf96f..ccd127b 100644 --- a/LuskiServer/Controllers/v1/CreateAccountController.cs +++ b/LuskiServer/Controllers/v1/SocketAccountController.cs @@ -13,16 +13,103 @@ namespace LuskiServer.Controllers.v1; [ApiVersion(1)] [ApiController] -public class CreateAccountController : ControllerBase +public class SocketAccountController : Controller { + /// + /// Make a get request to this endpoint to login to your account on the server. + /// + /// Encrypted email for account. + /// Hashed Password for account. + /// Plain text RSA key for server to respond with. + /// + [HttpGet] + [Produces(MediaTypeNames.Application.Json)] + [ProducesResponseType(typeof(Login), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(Login), StatusCodes.Status403Forbidden)] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "username")]string UsernameRaw, [FromHeader(Name = "password")]string PasRaw, [FromHeader(Name = "key")]string KeyRaw) + { + try + { + byte[] PasBytes, Username; + byte[] salt = new byte[100]; + try + { + using (RandomNumberGenerator provider = RandomNumberGenerator.Create()) + { + provider.GetBytes(salt); + } + try + { + PasBytes = Luski.Encryption.RemotePasswordEncrypt(Encryption.Generic.Encoders[(int)EncoderType.UTF16].GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(PasRaw), Luski.Encryption.Keys.PrivateKey)), salt); + Username = Encryption.RSA.Decrypt(Convert.FromBase64String(UsernameRaw), Luski.Encryption.Keys.PrivateKey); + + try + { + byte[] g = Encryption.RSA.Encrypt("Test data to send to client", KeyRaw, EncoderType.UTF8); + } + catch + { + return this.ShowError(ErrorCode.InvalidHeader, "The public keys you gave cant be used to encrypt data"); + } + } + catch + { + return this.ShowError(ErrorCode.InvalidHeader, "Make sure your login is encrypted with the server provided public key"); + } + } + catch (Exception ex) + { + if (ex.Message.Contains("not found")) return this.ShowError(ErrorCode.MissingHeader, "Missing login infermation"); + return this.ShowError(ex); + } + + if (!Tables.Users.TryRead(Users.ID, out long ID, Users.Username.CreateParameter(Username), + Users.Password.CreateParameter(PasBytes))) + return this.ShowError(ErrorCode.Forbidden, "Make sure our login info is correct"); + int num = new Random().Next(1000, 1000000000); + int num2 = new Random().Next(1000, 1000000000); + byte[] Timestamp = Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString()); + byte[] Number = Encoding.UTF8.GetBytes(num.ToString()); + byte[] Number2 = Encoding.UTF8.GetBytes(num2.ToString()); + string Token = $"{Convert.ToBase64String(Encoding.UTF8.GetBytes(ID.ToString()))}.{Convert.ToBase64String(Timestamp)}.{Convert.ToBase64String(Number)}.{Convert.ToBase64String(Number2)}"; + + Luski.Snowflake id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + long kid = id.ID; + Tables.Keys.Insert( + Keys.ID.CreateParameter(kid), + Keys.EncryptionType.CreateParameter(EncryptionType.RSA), + Keys.Owner.CreateParameter(ID), + Keys.KeyData.CreateParameter(Encoding.UTF8.GetBytes(KeyRaw))); + id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + Tables.Sessions.Insert( + Sessions.ID.CreateParameter(id.ID), + Sessions.User.CreateParameter(ID), + Sessions.LoginToken.CreateParameter(Token), + Sessions.SessionKey.CreateParameter(kid), + Sessions.WSSTCP.CreateParameter(string.Empty), + Sessions.Token.CreateParameter(string.Empty)); + Thread t = new(o => RegToken((string?)o)); + t.Start(Token); + return StatusCode(StatusCodes.Status202Accepted, new Login() + { + login_token = Token + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + /// /// Make a post request to this endpoint for registering an account on the server. /// - /// Encrypted email for account - /// Hashed Password for account - /// Plain text Username - /// Plain text RSA key for server to respond with - /// Raw Picture data for profile + /// Encrypted email for account. + /// Hashed Password for account. + /// Plain text Username. + /// Plain text RSA key for server to respond with. + /// Raw Picture data for profile. /// [HttpPost] [DisableRequestSizeLimit] @@ -81,11 +168,11 @@ public class CreateAccountController : ControllerBase string Token = $"{Convert.ToBase64String(ID)}.{Convert.ToBase64String(Timestamp)}.{Convert.ToBase64String(Number)}.{Convert.ToBase64String(Number2)}"; pfp = GetProfilePictureType(Encoding.UTF8.GetString(Body).ToUpper()); - + long uid = id.ID; Tables.Users.Insert( - Users.ID.CreateParameter(id.ID), + Users.ID.CreateParameter(uid), Users.DisplayName.CreateParameter(DisplayName!.Replace("'", "\'")), - Users.SelectedChannel.CreateParameter(0), //TODO set to default + Users.SelectedChannel.CreateParameter(0), //TODO set to default channel Users.Status.CreateParameter(Status.Offline), Users.PictureType.CreateParameter(pfp), Users.Picture.CreateParameter(Body), @@ -93,12 +180,23 @@ public class CreateAccountController : ControllerBase Users.Username.CreateParameter(Username), Users.Password.CreateParameter(PasBytes), Users.Salt.CreateParameter(salt), - Users.LoginToken.CreateParameter(Token), - Users.SessionKey.CreateParameter(KeyRaw), - Users.WSSTCP.CreateParameter(string.Empty), - Users.Token.CreateParameter(string.Empty), - Users.OfflineData.CreateParameter(Array.Empty()), - Users.OffileKey.CreateParameter(string.Empty)); + Users.OfflineData.CreateParameter(Array.Empty()), + Users.OffileKey.CreateParameter(0)); + id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + long kid = id.ID; + Tables.Keys.Insert( + Keys.ID.CreateParameter(kid), + Keys.EncryptionType.CreateParameter(EncryptionType.RSA), + Keys.Owner.CreateParameter(uid), + Keys.KeyData.CreateParameter(Encoding.UTF8.GetBytes(KeyRaw))); + id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + Tables.Sessions.Insert( + Sessions.ID.CreateParameter(id.ID), + Sessions.User.CreateParameter(uid), + Sessions.LoginToken.CreateParameter(Token), + Sessions.SessionKey.CreateParameter(kid), + Sessions.WSSTCP.CreateParameter(string.Empty), + Sessions.Token.CreateParameter(string.Empty)); Thread t = new(o => RegToken((string?)o)); t.Start(Token); return StatusCode(201, new Login() @@ -113,7 +211,7 @@ public class CreateAccountController : ControllerBase return this.ShowError(ex); } } - + private static PictureType GetProfilePictureType(string headerCode) { if (headerCode.StartsWith("FFD8FFE0")) @@ -141,7 +239,7 @@ public class CreateAccountController : ControllerBase return PictureType.png; } } - + /// /// Cheaks to see Username is free /// @@ -162,9 +260,9 @@ public class CreateAccountController : ControllerBase { if (token == null) return; long id = long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(token.Split('.')[0]))); - Tables.Users.Update(Users.ID, id, Users.LoginToken.CreateParameter(token)); + Tables.Sessions.Update(Sessions.ID, id, Sessions.LoginToken.CreateParameter(token)); Thread.Sleep(30000); - Tables.Users.Update(Users.ID, id, Users.LoginToken.CreateParameter(string.Empty)); + Tables.Sessions.Update(Sessions.ID, id, Sessions.LoginToken.CreateParameter(string.Empty)); } catch (Exception ex) { diff --git a/LuskiServer/Controllers/v1/SocketBulkMessageController.cs b/LuskiServer/Controllers/v1/SocketBulkMessageController.cs index 93ef49b..00ed585 100644 --- a/LuskiServer/Controllers/v1/SocketBulkMessageController.cs +++ b/LuskiServer/Controllers/v1/SocketBulkMessageController.cs @@ -4,7 +4,6 @@ using LuskiServer.Classes.TableDef; using LuskiServer.Classes.WebTypes; using LuskiServer.Enums; using Microsoft.AspNetCore.Mvc; -using ServerDatabase; namespace LuskiServer.Controllers.v1; @@ -25,7 +24,7 @@ public class SocketBulkMessageController : ControllerBase 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"); if (!Luski.HasAccessToChannel(ID, Channel_Id, ServerPermissions.ReadMessageHistory)) - return this.ResponseToResult(new HTTPResponse() { error = ErrorCode.Forbidden }); + return this.ResponseCodeToResult(ErrorCode.Forbidden); if (Request.Headers.ContainsKey("messages")) _ = long.TryParse(Request.Headers["messages"].First(), out MessagesToDownload); if (MessagesToDownload > Max) MessagesToDownload = Max; string? MostRecentID = null; @@ -34,7 +33,7 @@ public class SocketBulkMessageController : ControllerBase { try { - bool HasMRID = Tables.Messages.TryRead(Messages.ID, new Order() { Assending = false, Type = Messages.TimeStamp.Name }, out long MRID, Messages.ChannelID.CreateParameter(Channel_Id)); + bool HasMRID = Tables.Messages.TryRead(Messages.ID, Messages.TimeStamp.GetDecendingOrder(), out long MRID, Messages.ChannelID.CreateParameter(Channel_Id)); Console.WriteLine(MRID); if (HasMRID) { @@ -56,7 +55,7 @@ public class SocketBulkMessageController : ControllerBase if (MostRecentID != null) { MessageRow[] rawmsgs = Tables.Messages.ReadRows((uint)MessagesToDownload, - new Order() { Assending = false, Type = Messages.TimeStamp.Name }, + Messages.TimeStamp.GetDecendingOrder(), Messages.TimeStamp.CreateParameter(new Luski.Snowflake(long.Parse(MostRecentID)).Timestamp, sign), Messages.ChannelID.CreateParameter(Channel_Id)); @@ -68,7 +67,7 @@ public class SocketBulkMessageController : ControllerBase { content = Convert.ToBase64String(Row.Context), encoder_type = Row.EncoderType, - encryption_type = Row.EncryptionType, + encryption_key = Row.EncryptionKey, channel_id = Row.ChannelID, user_id = Row.AuthorID, id = Row.ID, @@ -87,9 +86,9 @@ public class SocketBulkMessageController : ControllerBase name = Convert.ToBase64String(fileraw.Name), size = ulong.Parse(fileraw.Size.ToString()), name_encoder_type = fileraw.NameEncoderType, - name_encryption_type = fileraw.NameEncryptionType, + name_encryption_key = fileraw.NameEncryptionKey, encoder_type = fileraw.EncoderType, - encryption_type = fileraw.EncryptionType + encryption_key = fileraw.EncryptionKey }; list.Add(file); } diff --git a/LuskiServer/Controllers/v1/SocketChannelController.cs b/LuskiServer/Controllers/v1/SocketChannelController.cs new file mode 100644 index 0000000..ebb8855 --- /dev/null +++ b/LuskiServer/Controllers/v1/SocketChannelController.cs @@ -0,0 +1,134 @@ +using Asp.Versioning; +using LuskiServer.Classes; +using LuskiServer.Classes.TableDef; +using LuskiServer.Classes.v1.OutGoing; +using LuskiServer.Classes.WebTypes; +using LuskiServer.Enums; +using Microsoft.AspNetCore.Mvc; + +namespace LuskiServer.Controllers.v1; + +[ApiVersion(1)] +[ApiController] +public class SocketChannelController : ControllerBase +{ + [HttpPost] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Post([FromBody]UserChannelRequest ChanReq) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Luski.HasAccessToCategory(ID, ChanReq.parent, ServerPermissions.CreateChannels)) return this.ResponseCodeToResult(ErrorCode.Forbidden); + DateTime epoch = Luski.Config.ServerEpoch; + List RoleOverides = new(), UserOverides = new(); + if (ChanReq.role_overides is not null && ChanReq.role_overides.Any()) + { + foreach (UserRoleOverideRequest over in ChanReq.role_overides) + { + Luski.Snowflake overSnowflake = Luski.Snowflake.GenerateSnowflake(epoch); + Tables.ServerRoleOverides.Insert( + ServerRoleOverides.ID.CreateParameter(overSnowflake.ID), + ServerRoleOverides.RoleID.CreateParameter(over.role_id), + ServerRoleOverides.Overides.CreateParameter(over.overides)); + RoleOverides.Add(overSnowflake.ID); + } + } + if (ChanReq.user_overides is not null && ChanReq.user_overides.Any()) + { + foreach (UserPermOverideRequest over in ChanReq.user_overides) + { + Luski.Snowflake overSnowflake = Luski.Snowflake.GenerateSnowflake(epoch); + Tables.UserRoleOverides.Insert( + UserRoleOverides.ID.CreateParameter(overSnowflake.ID), + UserRoleOverides.UserID.CreateParameter(over.user_id), + UserRoleOverides.Overides.CreateParameter(over.overides)); + UserOverides.Add(overSnowflake.ID); + } + } + + epoch = DateTime.UtcNow.Date; + Luski.Snowflake chanSnowflake = Luski.Snowflake.GenerateSnowflake(epoch); + Tables.Channels.Insert( + Channels.ID.CreateParameter(chanSnowflake.ID), + Channels.Parent.CreateParameter(ChanReq.parent), + Channels.Type.CreateParameter(ChanReq.type), + Channels.Epoch.CreateParameter(epoch.Date), + Channels.Name.CreateParameter(Convert.FromBase64String(ChanReq.name)), + Channels.Description.CreateParameter(Convert.FromBase64String(ChanReq.description)), + Channels.RoleOverides.CreateParameter(RoleOverides.ToArray()), + Channels.UserOverides.CreateParameter(UserOverides.ToArray()), + Channels.TitleEncryptionKey.CreateParameter(ChanReq.title_encryption_key), + Channels.DescriptionEncryptionKey.CreateParameter(ChanReq.description_encryption_key), + Channels.EncoderBlacklist.CreateParameter(ChanReq.encoder_blacklist), + Channels.EncryptionBlacklist.CreateParameter(ChanReq.encryption_blacklist), + Channels.EncryptionTypes.CreateParameter(ChanReq.encryption_types), + Channels.TitleEncoderType.CreateParameter(ChanReq.title_encoder_type), + Channels.DescriptionEncoderType.CreateParameter(ChanReq.description_encoder_type), + Channels.EncoderTypes.CreateParameter(ChanReq.encoder_types)); + return this.ResponseToResult(new UserChannelRequest(){ id = ID}); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpDelete] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Delete([FromHeader(Name = "id")]long Channel) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Luski.HasAccessToCategory(ID, Channel, ServerPermissions.DeleteChannels)) return this.ResponseCodeToResult(ErrorCode.Forbidden); + Tables.Channels.DeleteRow(Channels.ID.CreateParameter(Channel)); + Tables.Messages.DeleteRow(Messages.ChannelID.CreateParameter(Channel)); + return StatusCode(StatusCodes.Status202Accepted); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpPatch] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Patch([FromHeader(Name = "id")]long Channel) //TODO Add Channel edit latter + { + return null; + } + + [HttpGet] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "id")]long Channel) //TODO add channel get + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Luski.HasAccessToChannel(ID, Channel, ServerPermissions.ViewChannels)) return this.ResponseCodeToResult(ErrorCode.Forbidden); + ChannelRow chan = Tables.Channels.ReadRow(Channels.ID.CreateParameter(Channel)); + return this.ResponseToResult(new ChannelResponse() + { + title = Convert.ToBase64String(chan.Name), + description = Convert.ToBase64String(chan.Description), + id = Channel, + type = chan.Type, + parent = chan.Parent, + epoch = chan.Epoch, + title_encryption_key = chan.TitleEncryptionKey, + description_encryption_key = chan.DescriptionEncryptionKey, + encoder_blacklist = chan.EncoderBlacklist, + encryption_blacklist = chan.EncryptionBlacklist, + encryption_types = chan.EncryptionTypes, + title_encoder_type = chan.TitleEncoderType, + description_encoder_type = chan.DescriptionEncoderType, + encoder_types = chan.EncoderTypes + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketFileController.cs b/LuskiServer/Controllers/v1/SocketFileController.cs new file mode 100644 index 0000000..5b7e2dd --- /dev/null +++ b/LuskiServer/Controllers/v1/SocketFileController.cs @@ -0,0 +1,94 @@ +using System.Net.Mime; +using System.Text; +using Asp.Versioning; +using JacobTechEncryption; +using JacobTechEncryption.Enums; +using LuskiServer.Classes; +using LuskiServer.Classes.TableDef; +using LuskiServer.Classes.v1.OutGoing; +using LuskiServer.Enums; +using Microsoft.AspNetCore.Mvc; + +namespace LuskiServer.Controllers.v1; + +[ApiVersion(1)] +[ApiController] +public class SocketFileController : ControllerBase +{ + [HttpGet] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "id")] long File_id, [FromHeader(Name = "channel")] long Channel_id) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Files.TryRead(Files.Data, out byte[] raw, Files.ID.CreateParameter(File_id)) || !Luski.HasAccessToChannel(ID, Channel_id, ServerPermissions.ReadMessageHistory)) return this.ResponseCodeToResult(ErrorCode.Forbidden); + + return File(raw, MediaTypeNames.Application.Octet); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpDelete] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Delete([FromHeader(Name = "id")] long File_id) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Files.TryRead(Files.Owner, out long raw, Files.ID.CreateParameter(File_id)) || raw != ID) return this.ResponseCodeToResult(ErrorCode.Forbidden); + Tables.Files.Update(Files.ID, File_id, + Files.Data.CreateParameter(Array.Empty()), + Files.NameEncoderType.CreateParameter(EncoderType.UTF8), + Files.NameEncryptionKey.CreateParameter(0), + Files.Name.CreateParameter(Encoding.UTF8.GetBytes("Deleted File")), + Files.Size.CreateParameter(0), + Files.EncryptionKey.CreateParameter(0)); + return StatusCode(StatusCodes.Status202Accepted); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpPost] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Post([FromBody] byte[] data, [FromHeader(Name = "name_encoder")] EncoderType nameEncoderNum, [FromHeader(Name = "name_encryption")]long nameEncryptionRaw, [FromHeader(Name = "encoder")] EncoderType EncoderNum, [FromHeader(Name = "encryption")]long EncryptionRaw, [FromHeader(Name = "name")]string name) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + + byte[] hash = Encryption.Hashing.SHA256(data); + if (Tables.Files.TryRead(Files.ID, out long ido, Files.Hash.CreateParameter(hash))) + return this.ResponseToResult(new ServerFile() { id = ido }); + + ido = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch).ID; + + Tables.Files.Insert( + Files.ID.CreateParameter(ido), + Files.Size.CreateParameter(data.Length), + Files.Name.CreateParameter(Convert.FromBase64String(name)), + Files.NameEncoderType.CreateParameter(nameEncoderNum), + Files.NameEncryptionKey.CreateParameter(nameEncryptionRaw), + Files.Data.CreateParameter(data), + Files.EncoderType.CreateParameter(EncoderNum), + Files.EncryptionKey.CreateParameter(EncryptionRaw), + Files.Hash.CreateParameter(hash), + Files.Owner.CreateParameter(ID), + Files.Public.CreateParameter(false), + Files.AllowedChannels.CreateParameter(Array.Empty())); + return this.ResponseToResult(new ServerFile() { id = ido }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + //TODO Add File edit latter +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketMessageController.cs b/LuskiServer/Controllers/v1/SocketMessageController.cs index f513948..8e0a5e2 100644 --- a/LuskiServer/Controllers/v1/SocketMessageController.cs +++ b/LuskiServer/Controllers/v1/SocketMessageController.cs @@ -1,3 +1,4 @@ +using System.Net.Mime; using Asp.Versioning; using JacobTechEncryption.Enums; using LuskiServer.Classes; @@ -8,6 +9,7 @@ using LuskiServer.Classes.WebTypes; using LuskiServer.Enums; using LuskiServer.Enums.ServerComs; using Microsoft.AspNetCore.Mvc; +using ServerDatabase; namespace LuskiServer.Controllers.v1; @@ -15,15 +17,64 @@ namespace LuskiServer.Controllers.v1; [ApiController] public class SocketMessageController : ControllerBase { - [HttpPost] - [DisableRequestSizeLimit] + [HttpGet] [Route(Luski.Info.Routes.Default.Base)] - public async Task Post([FromBody]ClientSendMessage data) + public IActionResult Get([FromHeader(Name = "msg_id")]long MSG_id) { try { if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; - if (!Luski.HasAccessToChannel(ID, data.ChannelID, ServerPermissions.SendMessages)) return this.ResponseToResult(new HTTPResponse() { error = ErrorCode.Forbidden }); + if (!Tables.Messages.TryRead(Messages.ChannelID, out long Channel_Id, Messages.ID.CreateParameter(MSG_id)) || + !Luski.HasAccessToChannel(ID, Channel_Id, ServerPermissions.ReadMessageHistory)) this.ResponseCodeToResult(ErrorCode.Forbidden); + MessageRow msgraw = Tables.Messages.ReadRow(Messages.ID.CreateParameter(MSG_id)); + SocketMessage msg = new() + { + user_id = msgraw.AuthorID, + content = Convert.ToBase64String(msgraw.Context), + id = MSG_id, + channel_id = Channel_Id + }; + if (msgraw.Files.Any()) + { + List list = new(); + foreach (long b in msgraw.Files) + { + FileRow fileraw = Tables.Files.ReadRow(Files.ID.CreateParameter(b)); + Classes.WebTypes.File file = new() + { + data = null!, + id = b, + name = Convert.ToBase64String(fileraw.Name), + size = ulong.Parse(fileraw.Size.ToString()), + name_encoder_type = fileraw.NameEncoderType, + name_encryption_key = fileraw.NameEncryptionKey, + encoder_type = fileraw.EncoderType, + encryption_key = fileraw.EncryptionKey + }; + list.Add(file); + } + + msg.files = list.ToArray(); + } + + return this.ResponseToResult(msg); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpPost] + [DisableRequestSizeLimit] + [Consumes(typeof(ClientSendMessage), MediaTypeNames.Application.Json)] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Post([FromBody]ClientSendMessage data) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!Luski.HasAccessToChannel(ID, data.ChannelID, ServerPermissions.SendMessages)) return this.ResponseCodeToResult(ErrorCode.Forbidden); 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)); MessageEvent MessageEvent = new() @@ -41,7 +92,7 @@ public class SocketMessageController : ControllerBase Messages.TimeStamp.CreateParameter(Id.Timestamp), Messages.Files.CreateParameter(data.Files), Messages.EncoderType.CreateParameter(data.Encoding), - Messages.EncryptionType.CreateParameter(data.Encryption)); + Messages.EncryptionKey.CreateParameter(data.EncryptionKey)); WSS.SendData(SendType.ID_Group, new ServerEvent() { Type = DataType.MessageCreate, @@ -50,9 +101,11 @@ public class SocketMessageController : ControllerBase Response.StatusCode = 201; return null!; } - catch (Exception ex) + catch (Exception e) { - return this.ShowError(ex); + return this.ShowError(e); } } + + //TODO Add Message edit latter } \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketUserController.cs b/LuskiServer/Controllers/v1/SocketUserController.cs new file mode 100644 index 0000000..dfe5bc0 --- /dev/null +++ b/LuskiServer/Controllers/v1/SocketUserController.cs @@ -0,0 +1,37 @@ +using Asp.Versioning; +using JacobTechEncryption; +using LuskiServer.Classes; +using LuskiServer.Classes.TableDef; +using LuskiServer.Classes.v1.OutGoing; +using LuskiServer.Enums; +using Microsoft.AspNetCore.Mvc; + +namespace LuskiServer.Controllers.v1; + +[ApiVersion(1)] +[ApiController] +public class SocketUserController : ControllerBase +{ + [HttpGet] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "id")]long Person) + { + try + { + if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (Person != ID && !Tables.Users.TryRead(Users.ID, out _, Users.ID.CreateParameter(Person))) return this.ShowError(ErrorCode.Forbidden, "User does not exist"); + return this.ResponseToResult(new UserResponse() + { + id = Person, + displayname = Tables.Users.Read(Users.DisplayName, Users.ID.CreateParameter(Person)), + picture_type = Tables.Users.Read(Users.PictureType, Users.ID.CreateParameter(Person)), + roles = Tables.Users.Read(Users.Roles, Users.ID.CreateParameter(Person)), + status = Tables.Users.Read(Users.Status, Users.ID.CreateParameter(Person)) + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } +} \ No newline at end of file diff --git a/LuskiServer/Enums/ServerPermissions.cs b/LuskiServer/Enums/ServerPermissions.cs index 3e71996..7a664a1 100644 --- a/LuskiServer/Enums/ServerPermissions.cs +++ b/LuskiServer/Enums/ServerPermissions.cs @@ -3,9 +3,18 @@ namespace LuskiServer.Enums; public enum ServerPermissions : long { ViewChannels, - ManageChannels, + MoveChannels, + EditChannels, + EditChannelPermissions, + CreateChannels, + DeleteChannels, ViewCategories, - ManageCategories, + MoveCategories, + EditCategories, + EditCategoryPermissions, + CreateCategories, + DeleteCategories, + DeleteKeys, ManageRoles, ViewLogs, ManageServer, diff --git a/LuskiServer/Interfaces/IWebResponse.cs b/LuskiServer/Interfaces/IWebResponse.cs new file mode 100644 index 0000000..2b518e3 --- /dev/null +++ b/LuskiServer/Interfaces/IWebResponse.cs @@ -0,0 +1,6 @@ +namespace LuskiServer.Interfaces; + +public interface IWebResponse +{ + +} \ No newline at end of file diff --git a/LuskiServer/LuskiServer.csproj b/LuskiServer/LuskiServer.csproj index bb535c6..9d3da0d 100644 --- a/LuskiServer/LuskiServer.csproj +++ b/LuskiServer/LuskiServer.csproj @@ -23,8 +23,8 @@ - - + + diff --git a/LuskiServer/Program.cs b/LuskiServer/Program.cs index 1388aa1..7bc5957 100644 --- a/LuskiServer/Program.cs +++ b/LuskiServer/Program.cs @@ -76,14 +76,22 @@ if (!Tables.Roles.TryRead(Roles.ID, out _, Roles.ID.CreateParameter(0))) ); } +if (!Tables.Keys.TryRead(Keys.ID, out _, Keys.ID.CreateParameter(0))) +{ + Tables.Keys.Insert( + Keys.ID.CreateParameter(0), + Keys.EncryptionType.CreateParameter(EncryptionType.None), + Keys.KeyData.CreateParameter(Array.Empty())); +} + if (!Tables.Categories.TryRead(Categories.ID, out _, Categories.ID.CreateParameter(0))) { Tables.Categories.Insert( Categories.ID.CreateParameter(0), - Categories.Name.CreateParameter("server"), + Categories.Name.CreateParameter(Encoding.UTF8.GetBytes("server")), Categories.Parent.CreateParameter(-1), Categories.Description.CreateParameter( - "The default category for the server. Everybody will see this category."), + Encoding.UTF8.GetBytes("The default category for the server. Everybody will see this category.")), Categories.RoleOverides.CreateParameter(new long[1] { 0 }) ); Tables.Channels.Insert( @@ -91,24 +99,19 @@ if (!Tables.Categories.TryRead(Categories.ID, out _, Categories.ID.CreateParamet Channels.Type.CreateParameter(ChannelType.TextAndVoice), Channels.Description.CreateParameter(Encoding.UTF8.GetBytes("Default chat for you to use in your new server")), Channels.Name.CreateParameter(Encoding.UTF8.GetBytes("Default Channel")), - Channels.Key.CreateParameter(Luski.Encryption.Keys.PublicKey), Channels.RoleOverides.CreateParameter(Array.Empty()), Channels.UserOverides.CreateParameter(Array.Empty()), - Channels.Epoch.CreateParameter(DateTime.UtcNow), - Channels.TitleEncryptionType.CreateParameter(EncryptionType.None), - Channels.DescriptionEncryptionType.CreateParameter(EncryptionType.None), - Channels.AllowedEncryptionTypes.CreateParameter(new [] { EncryptionType.RSA, EncryptionType.AES }), + Channels.Epoch.CreateParameter(DateTime.UtcNow.Date), + Channels.TitleEncryptionKey.CreateParameter(0), + Channels.DescriptionEncryptionKey.CreateParameter(0), + Channels.EncoderBlacklist.CreateParameter(true), + Channels.EncryptionBlacklist.CreateParameter(true), + Channels.EncryptionTypes.CreateParameter(Array.Empty()), Channels.TitleEncoderType.CreateParameter(EncoderType.UTF8), Channels.DescriptionEncoderType.CreateParameter(EncoderType.UTF8), - Channels.AllowedEncoderTypes.CreateParameter(new [] - { - EncoderType.UTF8, EncoderType.UTF16, - EncoderType.UTF32, EncoderType.ASCII, - EncoderType.Latin1, EncoderType.BigEndianUnicode - })); + Channels.EncoderTypes.CreateParameter(Array.Empty())); } - var builder = WebApplication.CreateBuilder( args ); // Add services to the container. @@ -183,7 +186,7 @@ builder.Services.AddSwaggerGen( var filePath = Path.Combine(AppContext.BaseDirectory, fileName); // integrate xml comments - options.IncludeXmlComments(filePath); + options.IncludeXmlComments(filePath, true); } ); var app = builder.Build(); diff --git a/LuskiServer/Properties/launchSettings.json b/LuskiServer/Properties/launchSettings.json index 3a1eef0..0623b73 100644 --- a/LuskiServer/Properties/launchSettings.json +++ b/LuskiServer/Properties/launchSettings.json @@ -14,7 +14,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "http://localhost:5288;http://10.100.0.153:5287", + "applicationUrl": "http://localhost:5288;http://10.100.0.10:5287", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -24,7 +24,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7173;http://localhost:5287", + "applicationUrl": "https://localhost:7173;http://10.100.0.10:5287", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }