diff --git a/LuskiServer/Classes/AppConfig.cs b/LuskiServer/Classes/AppConfig.cs index dfd2f95..64f4f37 100644 --- a/LuskiServer/Classes/AppConfig.cs +++ b/LuskiServer/Classes/AppConfig.cs @@ -25,6 +25,33 @@ public class AppConfig [JsonInclude] [JsonPropertyName("connection_name")] public string CustomeName { get; set; } = "Luski Server"; + [JsonInclude] + [JsonPropertyName("wss_ipv4")] + public string IPv4WSS { get; set; } = "127.0.0.1"; + [JsonInclude] + [JsonPropertyName("wss_ipv4_URL")] + public string? IPv4_URL_WSS { get; set; } = ""; + [JsonInclude] + [JsonPropertyName("wss_ipv4_overide")] + public string? IPv4_Overode_WSS { get; set; } = null; + [JsonInclude] + [JsonPropertyName("wss_ipv4_port")] + public int IPv4PortWSS { get; set; } = 80; + [JsonInclude] + [JsonPropertyName("wss_ipv4_secure")] + public bool IPv4SecureWSS { get; set; } = true; + [JsonInclude] + [JsonPropertyName("wss_ipv6")] + public string? IPv6WSS { get; set; } = null; + [JsonInclude] + [JsonPropertyName("wss_ipv6_URL")] + public string? IPv6_URL_WSS { get; set; } = ""; + [JsonInclude] + [JsonPropertyName("wss_ipv6_port")] + public int IPv6PortWSS { get; set; } = 0; + [JsonInclude] + [JsonPropertyName("wss_ipv6_secure")] + public bool IPv6SecureWSS { get; set; } = true; } [JsonSerializable(typeof(AppConfig))] diff --git a/LuskiServer/Classes/EXT.cs b/LuskiServer/Classes/EXT.cs index 9c0cb0c..1b3f2be 100644 --- a/LuskiServer/Classes/EXT.cs +++ b/LuskiServer/Classes/EXT.cs @@ -13,14 +13,15 @@ public static class EXT return ((long)(enu)).ToString(); } - public static bool CanTokenRequest(this ControllerBase Base, out long id, out IActionResult? result) + public static bool CanTokenRequest(this ControllerBase Base, out long id, out long sid, out IActionResult? result) { if (Base.Request.Headers.ContainsKey("token")) { - return ValidateToke(Base, out id, out result); + return ValidateToke(Base, out id, out sid, out result); } result = Base.ShowError(ErrorCode.MissingToken, "You did not provide a token"); id = 0; + sid = 0; return false; } @@ -63,15 +64,16 @@ public static class EXT }); } - private static bool CheckToken(string Token, ref long ID) + private static bool CheckToken(string Token, ref long ID, ref long SID) { try { - string id = Encoding.UTF8.GetString(Convert.FromBase64String(Token.Split('.')[0])); + string id = Encoding.UTF8.GetString(Convert.FromBase64String(Token.Split('.')[1])); string? tok = Tables.Sessions.Read(Sessions.Token, Sessions.ID.CreateParameter(long.Parse(id))); if (!string.IsNullOrWhiteSpace(tok) && tok == Token) { - ID = long.Parse(id); + SID = long.Parse(id); + ID = Tables.Sessions.Read(Sessions.User, Sessions.ID.CreateParameter(SID)); return true; } return false; @@ -82,16 +84,18 @@ public static class EXT } } - private static bool ValidateToke(ControllerBase Base, out long Id, out IActionResult? result) + private static bool ValidateToke(ControllerBase Base, out long Id, out long Sid, out IActionResult? result) { - long id = 0; - if (CheckToken(Base.Request.Headers["token"].First()!, ref id)) + long id = 0, sid = 0; + if (CheckToken(Base.Request.Headers["token"].First()!, ref id, ref sid)) { result = null; Id = id; + Sid = sid; return true; } Id = id; + Sid = sid; result = Base.ShowError(ErrorCode.InvalidToken, (string)null!); return false; } diff --git a/LuskiServer/Classes/Luski.cs b/LuskiServer/Classes/Luski.cs index 20aa4a7..03dc816 100644 --- a/LuskiServer/Classes/Luski.cs +++ b/LuskiServer/Classes/Luski.cs @@ -1,6 +1,8 @@ using System.Security.Cryptography; +using System.Text; using System.Text.Json; using System.Text.Json.Serialization.Metadata; +using JacobTechEncryption.Enums; using LuskiServer.Classes.TableDef; using LuskiServer.Enums; using Npgsql; @@ -11,6 +13,20 @@ namespace LuskiServer.Classes; public static class Luski { public static Database Database = null!; + + public static byte[] ToDB(this string s, EncoderType Encoder, long Encryption) + { + if (!Tables.Keys.TryReadRow(out KeyRow row, Keys.ID.CreateParameter(Encryption))) throw new Exception("No a key"); + switch (row.EncryptionType) + { + default: + return JacobTechEncryption.Encryption.Generic.Encoders[(int)Encoder].GetBytes(s); + case EncryptionType.RSA: + return JacobTechEncryption.Encryption.RSA.Encrypt(s, Encoding.UTF8.GetString(row.KeyData), Encoder); + case EncryptionType.AES: + return JacobTechEncryption.Encryption.AES.Encrypt(JacobTechEncryption.Encryption.Generic.Encoders[(int)Encoder].GetBytes(s), Encoding.UTF8.GetString(row.KeyData)); + } + } public static TResult GetSettings(string path, JsonTypeInfo TypeInfo, bool EndOnError = false, bool UpdateOldFile = true) where TResult : new() { @@ -83,7 +99,7 @@ public static class Luski } ServerPermissions[] pp = new[] - { ServerPermissions.ViewChannels, ServerPermissions.ViewCategories, ServerPermissions.ReadMessageHistory }; + { ServerPermissions.ViewThis, ServerPermissions.ReadMessageHistory }; using NpgsqlConnection dbConnection = Luski.Database.CreateConnection(); dbConnection.Open(); using NpgsqlCommand cmd = new(); @@ -181,11 +197,86 @@ public static class Luski return (GoodPerms.Count == RequiredPerms.Length); } + public static bool HasAccessToCategory(long User, long Category, out IReadOnlyList missing, params ServerPermissions[] OptionalPerms) + { + long[] UserRoleIDList = Tables.Users.Read(Users.Roles, Users.ID.CreateParameter(User)); + List pp = OptionalPerms.ToList(); + if (!pp.Contains(ServerPermissions.ViewThis)) pp.Add(ServerPermissions.ViewThis); + 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()}:")) + { + missing = pp.AsReadOnly(); + 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.ServerRoleOverides.Read(ServerRoleOverides.Overides, + ServerRoleOverides.ID.CreateParameter(CatRoleOveride)); + foreach (string o in overrids) + { + foreach (ServerPermissions p in pp) + { + if (o.StartsWith($"{p.GetNumberString()}:")) + { + missing = pp.AsReadOnly(); + 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) + { + foreach (ServerPermissions p in GoodPerms) + { + pp.Remove(p); + } + + missing = pp.AsReadOnly(); + return true; + } + else + { + foreach (ServerPermissions p in GoodPerms) + { + pp.Remove(p); + } + + missing = pp.AsReadOnly(); + return false; + } + } + 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); + if (!pp.Contains(ServerPermissions.ViewThis)) pp.Add(ServerPermissions.ViewThis); List GoodPerms = new(); long[] CatUserOverides = Tables.Categories.Read(Categories.UserOverides, Categories.ID.CreateParameter(Category)); foreach (long CatUserOveride in CatUserOverides) @@ -209,7 +300,7 @@ public static class Luski 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, + string[] overrids = Tables.ServerRoleOverides.Read(ServerRoleOverides.Overides, ServerRoleOverides.ID.CreateParameter(CatRoleOveride)); foreach (string o in overrids) { @@ -241,8 +332,7 @@ public static class Luski { long[] UserRoleIDList = Tables.Users.Read(Users.Roles, Users.ID.CreateParameter(User)); List pp = RequiredPerms.ToList(); - if (!pp.Contains(ServerPermissions.ViewChannels)) pp.Add(ServerPermissions.ViewChannels); - if (!pp.Contains(ServerPermissions.ViewCategories)) pp.Add(ServerPermissions.ViewCategories); + if (!pp.Contains(ServerPermissions.ViewThis)) pp.Add(ServerPermissions.ViewThis); List GoodPerms = new(); long[] ChanUserOverides = Tables.Channels.Read(Channels.UserOverides, Channels.ID.CreateParameter(Channel)); foreach (long ChanUserOveride in ChanUserOverides) @@ -266,7 +356,7 @@ public static class Luski 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, + string[] overrids = Tables.ServerRoleOverides.Read(ServerRoleOverides.Overides, ServerRoleOverides.ID.CreateParameter(ChanRoleOveride)); foreach (string o in overrids) { @@ -306,13 +396,17 @@ public static class Luski } } - // public static readonly DateTime ServerEpoch = new(2023, 1, 1, 0, 0, 0, 0); - public static long GetTimestampFromEpoch(DateTime Epoch) { double ts = Math.Round(DateTime.UtcNow.Subtract(Epoch).TotalMilliseconds, 0); return long.Parse(ts.ToString().Replace(".", string.Empty)); } + + public static long GetTimestampFromEpoch(DateTime Epoch, DateTime Current) + { + double ts = Math.Round(Current.Subtract(Epoch).TotalMilliseconds, 0); + return long.Parse(ts.ToString().Replace(".", string.Empty)); + } } public class Snowflake @@ -331,6 +425,13 @@ public static class Luski if (i > 0b_1111_1111_1111) i = 0; return new Snowflake((((Info.GetTimestampFromEpoch(Epoch) << 8) | Config.DataId) << 12) | i); } + + public static Snowflake GenerateSnowflake(DateTime Epoch, DateTime Current) + { + i++; + if (i > 0b_1111_1111_1111) i = 0; + return new Snowflake((((Info.GetTimestampFromEpoch(Epoch, Current) << 8) | Config.DataId) << 12) | i); + } public long ID { get; } public long Timestamp { get; } diff --git a/LuskiServer/Classes/ServerComs/CilentMessageSendEvent.cs b/LuskiServer/Classes/ServerComs/CilentMessageSendEvent.cs new file mode 100644 index 0000000..75ea67a --- /dev/null +++ b/LuskiServer/Classes/ServerComs/CilentMessageSendEvent.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; +using LuskiServer.Enums.ServerComs; + +namespace LuskiServer.Classes.ServerComs; + +public class CilentMessageSendEvent +{ + [JsonPropertyName("type")] + [JsonInclude] + public DataType? Type { get; set; } = DataType.Token!; + [JsonPropertyName("error")] + [JsonInclude] + public string Error { get; set; } = default!; +} \ No newline at end of file diff --git a/LuskiServer/Classes/ServerComs/MessageEvent.cs b/LuskiServer/Classes/ServerComs/MessageEvent.cs index 7b63e27..a3011ea 100644 --- a/LuskiServer/Classes/ServerComs/MessageEvent.cs +++ b/LuskiServer/Classes/ServerComs/MessageEvent.cs @@ -20,4 +20,14 @@ public class MessageEvent : IServerEvent [JsonInclude] [JsonPropertyName("files")] public long[] Files { get; set; } +} + +[JsonSerializable(typeof(MessageEvent))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + WriteIndented = false)] +internal partial class MessageEventContext : JsonSerializerContext +{ + } \ No newline at end of file diff --git a/LuskiServer/Classes/ServerComs/ServerEvent.cs b/LuskiServer/Classes/ServerComs/ServerEvent.cs index 40a54c2..e87d555 100644 --- a/LuskiServer/Classes/ServerComs/ServerEvent.cs +++ b/LuskiServer/Classes/ServerComs/ServerEvent.cs @@ -12,5 +12,15 @@ public class ServerEvent [JsonInclude] [JsonPropertyName("data")] - public IServerEvent Data { get; set; } + public object Data { get; set; } +} + +[JsonSerializable(typeof(ServerEvent))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + WriteIndented = false)] +internal partial class ServerEventContext : JsonSerializerContext +{ + } \ No newline at end of file diff --git a/LuskiServer/Classes/ServerComs/ServerSendSendEvent.cs b/LuskiServer/Classes/ServerComs/ServerSendSendEvent.cs index 7311cd8..b2ba6a4 100644 --- a/LuskiServer/Classes/ServerComs/ServerSendSendEvent.cs +++ b/LuskiServer/Classes/ServerComs/ServerSendSendEvent.cs @@ -20,4 +20,14 @@ public class ServerSendSendEvent [JsonInclude] [JsonPropertyName("ids")] public long[]? IDS { get; set; } = null; +} + +[JsonSerializable(typeof(ServerSendSendEvent))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + WriteIndented = false)] +internal partial class ServerSendSendEventContext : JsonSerializerContext +{ + } \ No newline at end of file diff --git a/LuskiServer/Classes/ServerComs/TokenEvent.cs b/LuskiServer/Classes/ServerComs/TokenEvent.cs new file mode 100644 index 0000000..6e8bf63 --- /dev/null +++ b/LuskiServer/Classes/ServerComs/TokenEvent.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; +using LuskiServer.Interfaces.ServerComs; + +namespace LuskiServer.Classes.ServerComs; + +public class TokenEvent : CilentMessageSendEvent, IServerEvent +{ + [JsonInclude] + [JsonPropertyName("token")] + public string Token { get; set; } + [JsonInclude] + [JsonPropertyName("session_token")] + public string? SessionToken { get; set; } = default!; +} + +[JsonSerializable(typeof(TokenEvent))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + WriteIndented = false)] +internal partial class TokenEventContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/LuskiServer/Classes/ServerComs/WSS.cs b/LuskiServer/Classes/ServerComs/WSS.cs index 175fbe2..abab217 100644 --- a/LuskiServer/Classes/ServerComs/WSS.cs +++ b/LuskiServer/Classes/ServerComs/WSS.cs @@ -1,9 +1,115 @@ +using System.Net; +using System.Runtime.InteropServices.JavaScript; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using LuskiServer.Classes.TableDef; using LuskiServer.Enums.ServerComs; +using WebSocketSharp; +using WebSocketSharp.Server; namespace LuskiServer.Classes.ServerComs; -public class WSS +public static class WSS { + public static WebSocketServer ServerIPv4 = null!, ServerIPv6 = null!; + public class CoreV1 : WebSocketBehavior + { + protected override void OnClose(CloseEventArgs e) + { + try + { + long id = Tables.Sessions.Read(TableDef.Sessions.ID, TableDef.Sessions.WSSTCP.CreateParameter(ID)); + Tables.Sessions.DeleteRow(TableDef.Sessions.ID.CreateParameter(id)); + } + catch (Exception exception) + { + Console.WriteLine(exception); + } + base.OnClose(e); + } + + protected override void OnMessage(MessageEventArgs e) + { + ServerSendSendEvent? BaseMessage = JsonSerializer.Deserialize(e.Data, ServerSendSendEventContext.Default.ServerSendSendEvent); + if (BaseMessage is not null) + { + switch (BaseMessage.SendType) + { + case SendType.All: + switch (BaseMessage.Data.Type) + { + case DataType.MessageCreate: + MessageEvent msg = (BaseMessage.Data.Data as MessageEvent)!; + break; + } + break; + case SendType.ID_Group: + switch (BaseMessage.Data.Type) + { + case DataType.MessageCreate: + MessageEvent msg = (BaseMessage.Data.Data as MessageEvent)!; + string raw = JsonSerializer.Serialize(msg, MessageEventContext.Default.MessageEvent); + foreach (long user in BaseMessage.IDS!) + { + if (Tables.Sessions.TryReadRows(out SessionsRow[] rows, TableDef.Sessions.User.CreateParameter(user))) + { + foreach (SessionsRow row in rows) + { + Sessions.SendTo(raw, row.WSSTCP); + } + } + } + break; + } + break; + case SendType.Client: + switch (BaseMessage.Data.Type) + { + case DataType.Token: + TokenEvent te = JsonSerializer.Deserialize(BaseMessage.Data.Data.ToString()!, TokenEventContext.Default.TokenEvent)!; + if (Tables.Sessions.TryReadRow(out SessionsRow row, + TableDef.Sessions.LoginToken.CreateParameter(te.Token))) + { + string Token = $"{Convert.ToBase64String(Encoding.UTF8.GetBytes(row.User.ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(row.ID.ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(new Random().Next(0, 1000000).ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(new Random().Next(0, 1000000).ToString()))}"; + te.Token = Token; + te.Type = DataType.Token; + Tables.Sessions.Update(TableDef.Sessions.ID, row.ID, TableDef.Sessions.LoginToken.CreateParameter(string.Empty), TableDef.Sessions.Token.CreateParameter(Token), TableDef.Sessions.WSSTCP.CreateParameter(ID)); + Token = $"{Convert.ToBase64String(Encoding.UTF8.GetBytes(row.User.ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(new Random().Next(0, 1000000).ToString()))}.{Convert.ToBase64String(Encoding.UTF8.GetBytes(new Random().Next(0, 1000000).ToString()))}"; + te.SessionToken = Token; + Tables.SessionTokens.Insert( + SessionTokens.Token.CreateParameter(Token), + SessionTokens.AccountID.CreateParameter(row.User), + SessionTokens.TimeFilter.CreateParameter(DateTime.UtcNow.AddDays(5)), + SessionTokens.AddressFilter.CreateParameter(Array.Empty()), + SessionTokens.ID.CreateParameter(Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch).ID)); + string raw = JsonSerializer.Serialize(te, TokenEventContext.Default.TokenEvent); + Send(raw); + } + break; + } + break; + default: + break; + } + } + base.OnMessage(e); + } + } + + public static void Init(string IPv4, int IPv4_Port, string IPv4_URL, bool IPv4_Secure = true, string? IPv6 = null, string? IPv6_URL = null, int IPv6_Port = 0, bool IPv6_Secure = true) + { + ServerIPv4 = new WebSocketServer(IPAddress.Parse(IPv4), IPv4_Port, IPv4_Secure); + ServerIPv4.AddWebSocketService($"{IPv4_URL}v1"); + ServerIPv4.Start(); + if (IPv6 is not null) + { + ServerIPv6 = new WebSocketServer(IPAddress.Parse(IPv6), IPv6_Port, IPv6_Secure); + ServerIPv6.AddWebSocketService($"{IPv6_URL}v1"); + ServerIPv6.Start(); + } + } + public static void SendData(SendType SendType, ServerEvent Event, params long[] IDS) { ServerSendSendEvent SSSE = new() diff --git a/LuskiServer/Classes/TableDef/Categories.cs b/LuskiServer/Classes/TableDef/Categories.cs index 7a22fe7..e299798 100644 --- a/LuskiServer/Classes/TableDef/Categories.cs +++ b/LuskiServer/Classes/TableDef/Categories.cs @@ -9,6 +9,7 @@ public static class Categories { public static TableColumn ID { get; } = new("id", true); public static TableColumn Name { get; } = new("name") { DefaultValue = Encoding.UTF8.GetBytes("New Category") }; + public static TableColumn Color { get; } = new("color") {DefaultValue = "ÿÿÿÿ" }; 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() }; diff --git a/LuskiServer/Classes/TableDef/Channels.cs b/LuskiServer/Classes/TableDef/Channels.cs index 6b72685..e0a34f5 100644 --- a/LuskiServer/Classes/TableDef/Channels.cs +++ b/LuskiServer/Classes/TableDef/Channels.cs @@ -10,6 +10,7 @@ public static class Channels { public static TableColumn ID { get; } = new("id", true); public static TableColumn Parent { get; } = new("parent") { DefaultValue = -1 }; + public static TableColumn Color { get; } = new("color") {DefaultValue = "ÿÿÿÿ" }; 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") }; @@ -18,11 +19,11 @@ public static class Channels 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 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 EncryptionKeys { get; } = new("encryption_keys") { DefaultValue = new long[]{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 }; + public static TableColumn PictureType { get; } = new("picture_type") {DefaultValue = Enums.PictureType.png }; + public static TableColumn Picture { get; } = new("picture"); public static TableColumn EncoderTypes { get; } = new("encoder_types") { DefaultValue = new [] { EncoderType.UTF8, EncoderType.UTF16, diff --git a/LuskiServer/Classes/TableDef/Files.cs b/LuskiServer/Classes/TableDef/Files.cs index 8a90003..e64a926 100644 --- a/LuskiServer/Classes/TableDef/Files.cs +++ b/LuskiServer/Classes/TableDef/Files.cs @@ -8,6 +8,7 @@ public static class Files { public static TableColumn ID { get; } = new("id", true); public static TableColumn Owner { get; } = new("owner"); + public static TableColumn Channel { get; } = new("channel"); public static TableColumn Public { get; } = new("public_download"); public static TableColumn AllowedChannels { get; } = new("channels"); public static TableColumn Size { get; } = new("size"); diff --git a/LuskiServer/Classes/TableDef/Roles.cs b/LuskiServer/Classes/TableDef/Roles.cs index 6e87147..40c75b9 100644 --- a/LuskiServer/Classes/TableDef/Roles.cs +++ b/LuskiServer/Classes/TableDef/Roles.cs @@ -8,6 +8,8 @@ public static class Roles { public static TableColumn ID { get; } = new("id", true); public static TableColumn Name { get; } = new("name"); + public static TableColumn DisplayName { get; } = new("display_name") {DefaultValue = string.Empty}; + public static TableColumn Index { get; } = new("index") {DefaultValue = 0 }; public static TableColumn Color { get; } = new("color"); public static TableColumn Description { get; } = new("description"); public static TableColumn ServerPermissions { get; } = new("server_perms"); diff --git a/LuskiServer/Classes/TableDef/Server.cs b/LuskiServer/Classes/TableDef/Server.cs index cdbd31f..00532db 100644 --- a/LuskiServer/Classes/TableDef/Server.cs +++ b/LuskiServer/Classes/TableDef/Server.cs @@ -11,7 +11,7 @@ public static class Server public static TableColumn Picture { get; } = new("picture") { DefaultValue = Array.Empty() }; public static TableColumn Name { get; } = new("name") { DefaultValue = "Luski Server" }; public static TableColumn Description { get; } = new("description") { DefaultValue = "description" }; - public static TableColumn Owner { get; } = new("owner") { DefaultValue = 0 }; + public static TableColumn Owner { get; } = new("owner") { DefaultValue = -1 }; } [TableRow(typeof(Server))] diff --git a/LuskiServer/Classes/TableDef/SessionTokens.cs b/LuskiServer/Classes/TableDef/SessionTokens.cs index 37f08f0..09d9ce2 100644 --- a/LuskiServer/Classes/TableDef/SessionTokens.cs +++ b/LuskiServer/Classes/TableDef/SessionTokens.cs @@ -7,7 +7,7 @@ public static class SessionTokens { public static TableColumn ID { get; } = new("id", true); public static TableColumn AccountID { get; } = new("account_id"); - public static TableColumn Token { get; } = new("token"); + public static TableColumn Token { get; } = new("token"); public static TableColumn AddressFilter { get; } = new("address_filter"); public static TableColumn TimeFilter { get; } = new("date_filter"); } diff --git a/LuskiServer/Classes/TableDef/Sessions.cs b/LuskiServer/Classes/TableDef/Sessions.cs index 6dc3c9c..3a6b8ba 100644 --- a/LuskiServer/Classes/TableDef/Sessions.cs +++ b/LuskiServer/Classes/TableDef/Sessions.cs @@ -6,11 +6,12 @@ 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 User { get; } = new("userid"); 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"); + public static TableColumn StorageID { get; } = new("storage_id"); } [TableRow(typeof(Sessions))] public partial class SessionsRow diff --git a/LuskiServer/Classes/TableDef/Storage.cs b/LuskiServer/Classes/TableDef/Storage.cs new file mode 100644 index 0000000..ef60a7f --- /dev/null +++ b/LuskiServer/Classes/TableDef/Storage.cs @@ -0,0 +1,19 @@ +using ServerDatabase; +using ServerDatabase.SourceGenerator; + +namespace LuskiServer.Classes.TableDef; + +public static class Storage +{ + public static TableColumn ID { get; } = new("id", true); + public static TableColumn AccountID { get; } = new("account_id"); + public static TableColumn Data { get; } = new("data"); + public static TableColumn Password { get; } = new("password"); + public static TableColumn OffileKey { get; } = new("offline_key"); +} + +[TableRow(typeof(Storage))] +public partial class StorageRow +{ + +} \ No newline at end of file diff --git a/LuskiServer/Classes/TableDef/Users.cs b/LuskiServer/Classes/TableDef/Users.cs index 5ba14a6..14d8230 100644 --- a/LuskiServer/Classes/TableDef/Users.cs +++ b/LuskiServer/Classes/TableDef/Users.cs @@ -16,8 +16,6 @@ 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 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 ce1fed4..8ef5b26 100644 --- a/LuskiServer/Classes/Tables.cs +++ b/LuskiServer/Classes/Tables.cs @@ -14,6 +14,7 @@ public static class Tables 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 Storage { get; } = new("storage", 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!); diff --git a/LuskiServer/Classes/WebTypes/File.cs b/LuskiServer/Classes/WebTypes/File.cs index 95b5797..9e0446f 100644 --- a/LuskiServer/Classes/WebTypes/File.cs +++ b/LuskiServer/Classes/WebTypes/File.cs @@ -10,8 +10,8 @@ public class File public EncoderType encoder_type { get; set; } = default!; public EncoderType name_encoder_type { get; set; } = default!; public long encryption_key { get; set; } = default!; + public long channel { 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/Role.cs b/LuskiServer/Classes/WebTypes/Role.cs new file mode 100644 index 0000000..543f3f5 --- /dev/null +++ b/LuskiServer/Classes/WebTypes/Role.cs @@ -0,0 +1,15 @@ +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.WebTypes; + +public class Role : IWebResponse +{ + public long id { get; set; } + public string name { get; set; } + public string display_name { get; set; } + public int index { get; set; } + public string color { get; set; } + public string description { get; set; } + public Enums.ServerPermissions[] server_permissions { get; set; } + public long[] members_list { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/SocketMessage.cs b/LuskiServer/Classes/WebTypes/SocketMessage.cs index 6ad0f30..6836722 100644 --- a/LuskiServer/Classes/WebTypes/SocketMessage.cs +++ b/LuskiServer/Classes/WebTypes/SocketMessage.cs @@ -8,7 +8,7 @@ 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 string context { get; set; } = default!; public long encryption_key { get; set; } = default!; public EncoderType encoder_type { get; set; } = default!; public File[] files { get; set; } = default!; diff --git a/LuskiServer/Classes/WebTypes/UserCategoryRequest.cs b/LuskiServer/Classes/WebTypes/UserCategoryRequest.cs new file mode 100644 index 0000000..3349acd --- /dev/null +++ b/LuskiServer/Classes/WebTypes/UserCategoryRequest.cs @@ -0,0 +1,21 @@ +using JacobTechEncryption.Enums; +using LuskiServer.Enums; +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.WebTypes; + +public class UserCategoryRequest : IWebResponse +{ + public long id { get; set; } + public long parent { 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[] channels { get; set; } + public long[] inner_categories { get; set; } + public long description_encryption_key { get; set; } + public EncoderType title_encoder_type { get; set; } + public EncoderType description_encoder_type { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/WebTypes/UserChannelRequest.cs b/LuskiServer/Classes/WebTypes/UserChannelRequest.cs index 74aa1a2..f3b6d31 100644 --- a/LuskiServer/Classes/WebTypes/UserChannelRequest.cs +++ b/LuskiServer/Classes/WebTypes/UserChannelRequest.cs @@ -15,9 +15,7 @@ public class UserChannelRequest : IWebResponse 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 long[] encryption_keys { get; set; } public EncoderType title_encoder_type { get; set; } public EncoderType description_encoder_type { get; set; } public EncoderType[] encoder_types { get; set; } diff --git a/LuskiServer/Classes/v1/OutGoing/ChannelResponse.cs b/LuskiServer/Classes/v1/OutGoing/ChannelResponse.cs index 9df2816..6a5b603 100644 --- a/LuskiServer/Classes/v1/OutGoing/ChannelResponse.cs +++ b/LuskiServer/Classes/v1/OutGoing/ChannelResponse.cs @@ -6,8 +6,10 @@ namespace LuskiServer.Classes.v1.OutGoing; public class ChannelResponse : IWebResponse { - public string title { get; set; } = default!; + public string name { get; set; } = default!; + public string color { get; set; } = default!; public string description { get; set; } = default!; + public PictureType picture_type { get; set; } = default!; public long id { get; set; } = default!; public ChannelType type { get; set; } = default!; public long parent { get; set; } = default!; @@ -16,7 +18,9 @@ public class ChannelResponse : IWebResponse public long description_encryption_key { get; set; } = default!; public bool encoder_blacklist { get; set; } = default!; public bool encryption_blacklist { get; set; } = default!; - public EncryptionType[] encryption_types { get; set; } = default!; + public long[] encryption_keys { get; set; } = default!; + public long[] role_overides { get; set; } = default!; + public long[] member_overides { get; set; } = default!; public EncoderType title_encoder_type { get; set; } = default!; public EncoderType description_encoder_type { get; set; } = default!; public EncoderType[] encoder_types { get; set; } = default!; diff --git a/LuskiServer/Classes/v1/OutGoing/OfflineDataBlob.cs b/LuskiServer/Classes/v1/OutGoing/OfflineDataBlob.cs new file mode 100644 index 0000000..6319d57 --- /dev/null +++ b/LuskiServer/Classes/v1/OutGoing/OfflineDataBlob.cs @@ -0,0 +1,8 @@ +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.v1.OutGoing; + +public class OfflineDataBlob : IWebResponse +{ + public string[] data { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/v1/OutGoing/ServerInfoJson.cs b/LuskiServer/Classes/v1/OutGoing/ServerInfoJson.cs index 7715430..ad2d7cd 100644 --- a/LuskiServer/Classes/v1/OutGoing/ServerInfoJson.cs +++ b/LuskiServer/Classes/v1/OutGoing/ServerInfoJson.cs @@ -5,6 +5,7 @@ namespace LuskiServer.Classes.v1.OutGoing; public class ServerInfoJson : IWebResponse { public string name { get; set; } + public string wssv4 { get; set; } public string description { get; set; } public long owner { get; set; } } \ No newline at end of file diff --git a/LuskiServer/Classes/v1/OutGoing/StorageInfo.cs b/LuskiServer/Classes/v1/OutGoing/StorageInfo.cs new file mode 100644 index 0000000..8bd8bb4 --- /dev/null +++ b/LuskiServer/Classes/v1/OutGoing/StorageInfo.cs @@ -0,0 +1,10 @@ +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.v1.OutGoing; + +public class StorageInfo : IWebResponse +{ + public long id { get; set; } + public string password { get; set; } + public bool update { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/v1/OutGoing/UserCategoryRequest.cs b/LuskiServer/Classes/v1/OutGoing/UserCategoryRequest.cs new file mode 100644 index 0000000..666adf9 --- /dev/null +++ b/LuskiServer/Classes/v1/OutGoing/UserCategoryRequest.cs @@ -0,0 +1,22 @@ +using JacobTechEncryption.Enums; +using LuskiServer.Enums; +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.v1.OutGoing; + +public class UserCategoryResponse : IWebResponse +{ + public long id { get; set; } + public long parent { get; set; } + public string name { get; set; } + public string color { get; set; } = default!; + public string description { get; set; } + public long[] role_overides { get; set; } + public long[] member_overides { get; set; } + public long title_encryption_key { get; set; } + public long[] channels { get; set; } + public long[] inner_categories { get; set; } + public long description_encryption_key { get; set; } + public EncoderType title_encoder_type { get; set; } + public EncoderType description_encoder_type { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Classes/v1/OutGoing/UserKeysGetRequest.cs b/LuskiServer/Classes/v1/OutGoing/UserKeysGetRequest.cs new file mode 100644 index 0000000..0977dcf --- /dev/null +++ b/LuskiServer/Classes/v1/OutGoing/UserKeysGetRequest.cs @@ -0,0 +1,9 @@ +using LuskiServer.Classes.WebTypes; +using LuskiServer.Interfaces; + +namespace LuskiServer.Classes.v1.OutGoing; + +public class UserKeysGetRequest : IWebResponse +{ + public UserKeyGetRequest[] keys { get; set; } +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/KeysController.cs b/LuskiServer/Controllers/v1/KeysController.cs index 061692c..3361b31 100644 --- a/LuskiServer/Controllers/v1/KeysController.cs +++ b/LuskiServer/Controllers/v1/KeysController.cs @@ -5,6 +5,7 @@ using JacobTechEncryption; using JacobTechEncryption.Enums; using LuskiServer.Classes; using LuskiServer.Classes.TableDef; +using LuskiServer.Classes.v1.OutGoing; using LuskiServer.Classes.WebTypes; using LuskiServer.Enums; using Microsoft.AspNetCore.Mvc; @@ -46,7 +47,7 @@ public class KeysController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, 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); @@ -75,7 +76,7 @@ public class KeysController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; Luski.Snowflake sf = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); Tables.Keys.Insert( @@ -91,6 +92,76 @@ public class KeysController : ControllerBase } } + /// + /// Make a get request to this endpont to get a public key to a user. + /// + /// The user id you want to get a key from. + [HttpGet] + [Produces(MediaTypeNames.Application.Json)] + [ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)] + [Route(Luski.Info.Routes.Default.Base + "/UserKeys")] + public IActionResult GetUserKeys([FromRoute(Name = "id")]long userid) + { + try + { + if (!Tables.Users.TryRead(Users.ID, out _, Users.ID.CreateParameter(userid))) return this.ResponseCodeToResult(ErrorCode.Forbidden); + bool UserOnline = Tables.Sessions.TryReadRows(out SessionsRow[] usersessions, Sessions.User.CreateParameter(userid)); + List req = new(); + if (!UserOnline) + { + foreach (StorageRow StorageRow in Tables.Storage.ReadRows(uint.MaxValue, Storage.AccountID.CreateParameter(userid))) + { + KeyRow Row = Tables.Keys.ReadRow(Keys.ID.CreateParameter(StorageRow.OffileKey)); + req.Add(new UserKeyGetRequest() + { + id = Row.ID, + owner = Row.Owner, + encryption_type = Row.EncryptionType, + key_data = Convert.ToBase64String(Row.KeyData) + }); + } + + } + else + { + List b = new(); + foreach (SessionsRow sess in usersessions) + { + if (!b.Contains(sess.StorageID)) b.Add(sess.StorageID); + KeyRow Row = Tables.Keys.ReadRow(Keys.ID.CreateParameter(sess.SessionKey)); + req.Add(new UserKeyGetRequest() + { + id = Row.ID, + owner = Row.Owner, + encryption_type = Row.EncryptionType, + key_data = Convert.ToBase64String(Row.KeyData) + }); + } + + foreach (StorageRow StorageRow in Tables.Storage.ReadRows(uint.MaxValue, Storage.AccountID.CreateParameter(userid))) + { + if (b.Contains(StorageRow.ID)) continue; + KeyRow Row = Tables.Keys.ReadRow(Keys.ID.CreateParameter(StorageRow.OffileKey)); + req.Add(new UserKeyGetRequest() + { + id = Row.ID, + owner = Row.Owner, + encryption_type = Row.EncryptionType, + key_data = Convert.ToBase64String(Row.KeyData) + }); + } + } + return this.ResponseToResult(new UserKeysGetRequest() + { + keys = req.ToArray() + }); + } + catch (Exception ex) + { + return this.ShowError(ex); + } + } + /// /// Make a get request to this endpont to get a public key from the server. /// @@ -131,16 +202,16 @@ public class KeysController : ControllerBase [ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)] [ProducesResponseType(typeof(HTTPResponse), 500)] [Route(Luski.Info.Routes.Default.Base + "/SetOfflineKey")] - public IActionResult SetOfflineKey([FromBody]ClientKeyPostReqest keyreq, [FromHeader(Name = "token")]string? token) + public IActionResult SetOfflineKey([FromBody]ClientKeyPostReqest keyreq, [FromHeader(Name = "token")]string? token, [FromHeader(Name = "storage_id")]long StorageID) { try { string key = ""; - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; - 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"); + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; + byte[][]? data = Tables.Storage.Read(Storage.Data, Storage.ID.CreateParameter(ID)); + if (data is not null && data.Any()) return this.ShowError(ErrorCode.Forbidden, "you cant change your key until you download your data"); long k = 0; - if ((k = Tables.Users.Read(Users.OffileKey, Users.ID.CreateParameter(ID))) != 0) + if ((k = Tables.Storage.Read(Storage.OffileKey, Storage.ID.CreateParameter(ID))) != 0) { Tables.Keys.DeleteRow(Keys.ID.CreateParameter(k)); } @@ -150,8 +221,8 @@ public class KeysController : ControllerBase 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(sf.ID)); + Tables.Storage.Update(Storage.ID, ID, + Storage.OffileKey.CreateParameter(sf.ID)); return StatusCode(202); } catch (Exception ex) diff --git a/LuskiServer/Controllers/v1/OfflineDataController.cs b/LuskiServer/Controllers/v1/OfflineDataController.cs new file mode 100644 index 0000000..78d96dd --- /dev/null +++ b/LuskiServer/Controllers/v1/OfflineDataController.cs @@ -0,0 +1,128 @@ +using Asp.Versioning; +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 OfflineDataController : ControllerBase +{ + [HttpGet] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "token")]string? token, [FromHeader(Name = "storage_id")]long SID) + { + try + { + if (!this.CanTokenRequest(out long UID, out long SSID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Storage.TryReadRow(out StorageRow row, Storage.ID.CreateParameter(SID))) + return this.ResponseCodeToResult(ErrorCode.InvalidHeader); + if (row.AccountID != UID) return this.ResponseCodeToResult(ErrorCode.Forbidden); + List bbb = new(); + foreach (byte[]? blob in row.Data) + { + bbb.Add(Convert.ToBase64String(blob)); + } + Tables.Storage.Update(Storage.ID, SID, Storage.Data.CreateParameter(Array.Empty())); + return this.ResponseToResult(new OfflineDataBlob() + { + data = bbb.ToArray() + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpGet] + [Route(Luski.Info.Routes.Default.Base + "/Info")] + public IActionResult GetInfo([FromHeader(Name = "token")]string? token, [FromHeader(Name = "storage_id")]long SID) + { + try + { + if (!this.CanTokenRequest(out long UID, out long SSID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Storage.TryReadRow(out StorageRow row, Storage.ID.CreateParameter(SID))) + return this.ResponseCodeToResult(ErrorCode.InvalidHeader); + if (row.AccountID != UID) return this.ResponseCodeToResult(ErrorCode.Forbidden); + bool update = false; + if (Tables.Sessions.Read(Sessions.StorageID, Sessions.ID.CreateParameter(SSID)) == 0) + { + SessionsRow[] rows = Tables.Sessions.ReadRows(uint.MaxValue, Sessions.ID.CreateParameter(SSID), Sessions.StorageID.CreateParameter(SID)); + if (rows.Length == 0) + { + update = true; + } + Tables.Sessions.Update(Sessions.StorageID, SID, Sessions.ID.CreateParameter(SSID)); + } + return this.ResponseToResult(new StorageInfo() + { + password = Convert.ToBase64String(row.Password), + id = row.ID, + update = update + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpPatch] + [Route(Luski.Info.Routes.Default.Base + "/Info")] + public IActionResult SetInfo([FromBody]StorageInfo si, [FromHeader(Name = "token")]string? token, [FromHeader(Name = "storage_id")]long SID) + { + try + { + if (!this.CanTokenRequest(out long UID, out long SSID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Storage.TryReadRow(out StorageRow row, Storage.ID.CreateParameter(SID))) + return this.ResponseCodeToResult(ErrorCode.InvalidHeader); + if (row.AccountID != UID) return this.ResponseCodeToResult(ErrorCode.Forbidden); + Tables.Storage.Update(Storage.ID, SID, Storage.Password.CreateParameter(Convert.FromBase64String(si.password))); + + return this.ResponseToResult(new StorageInfo() + { + password = si.password, + id = row.ID, + update = false + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpPost] + [Route(Luski.Info.Routes.Default.Base + "/Info")] + public IActionResult PostInfo([FromBody]StorageInfo si, [FromHeader(Name = "token")]string? token) + { + try + { + Console.WriteLine("POST"); + if (!this.CanTokenRequest(out long UID, out long SSID, out IActionResult? toc) && toc != null) return toc; + Luski.Snowflake sf = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + Tables.Storage.Insert( + Storage.ID.CreateParameter(sf.ID), + Storage.Password.CreateParameter(Convert.FromBase64String(si.password)), + Storage.AccountID.CreateParameter(UID), + Storage.Data.CreateParameter(Array.Empty()), + Storage.OffileKey.CreateParameter(0)); + Tables.Sessions.Update(Sessions.StorageID, sf.ID, Sessions.ID.CreateParameter(SSID)); + + return this.ResponseToResult(new StorageInfo() + { + password = si.password, + id = sf.ID, + update = false + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketAccountController.cs b/LuskiServer/Controllers/v1/SocketAccountController.cs index ccd127b..be90684 100644 --- a/LuskiServer/Controllers/v1/SocketAccountController.cs +++ b/LuskiServer/Controllers/v1/SocketAccountController.cs @@ -8,6 +8,7 @@ using LuskiServer.Classes; using LuskiServer.Classes.TableDef; using LuskiServer.Enums; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Formatters; namespace LuskiServer.Controllers.v1; @@ -32,17 +33,15 @@ public class SocketAccountController : Controller 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); + if (!Tables.Users.TryRead(Users.Salt, out byte[]? salt, Users.Username.CreateParameter(Username))) + return this.ShowError(ErrorCode.Forbidden, "Make sure our login info is correct"); + PasBytes = Luski.Encryption.RemotePasswordEncrypt(PasRaw, salt); try { @@ -76,20 +75,80 @@ public class SocketAccountController : Controller Luski.Snowflake id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); long kid = id.ID; + Tables.Users.Update(Users.ID, ID, Users.Status.CreateParameter(Status.Invisible)); 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)); + Thread t = new(o => RegToken((string?)o, kid)); + t.Start(Token); + return StatusCode(StatusCodes.Status202Accepted, new Login() + { + login_token = Token + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + /// + /// 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 + "/AccessToken")] + public IActionResult GetT([FromHeader(Name = "token")]string TokenRaw, [FromHeader(Name = "key")]string KeyRaw) + { + try + { + string tok; + try + { + + tok = Encryption.RSA.Decrypt(Convert.FromBase64String(TokenRaw), + Luski.Encryption.Keys.PrivateKey, EncoderType.UTF16); + + 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"); + } + + if (!Tables.SessionTokens.TryRead(SessionTokens.AccountID, out long ID, SessionTokens.Token.CreateParameter(tok))) + 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)}"; + Tables.SessionTokens.DeleteRow(SessionTokens.Token.CreateParameter(tok)); + Luski.Snowflake id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + long kid = id.ID; + Tables.Users.Update(Users.ID, ID, Users.Status.CreateParameter(Status.Invisible)); + Tables.Keys.Insert( + Keys.ID.CreateParameter(kid), + Keys.EncryptionType.CreateParameter(EncryptionType.RSA), + Keys.Owner.CreateParameter(ID), + Keys.KeyData.CreateParameter(Encoding.UTF8.GetBytes(KeyRaw))); + Thread t = new(o => RegToken((string?)o, kid)); t.Start(Token); return StatusCode(StatusCodes.Status202Accepted, new Login() { @@ -113,18 +172,24 @@ public class SocketAccountController : Controller /// [HttpPost] [DisableRequestSizeLimit] - [Consumes(MediaTypeNames.Image.Jpeg, MediaTypeNames.Image.Gif, MediaTypeNames.Image.Tiff, "image/png")] + //[Consumes(MediaTypeNames.Image.Jpeg, MediaTypeNames.Image.Gif, MediaTypeNames.Image.Tiff, "image/png")] + //[Consumes(MediaTypeNames.Application.Octet)] [Produces(MediaTypeNames.Application.Json)] [ProducesResponseType(typeof(Login), StatusCodes.Status201Created)] [ProducesResponseType(typeof(Login), StatusCodes.Status403Forbidden)] [Route(Luski.Info.Routes.Default.Base)] - public IActionResult Post([FromBody]byte[] Body, [FromHeader(Name = "username")]string? UsernameRaw, [FromHeader(Name = "password")]string? PasRaw, [FromHeader(Name = "displayname")]string? DisplayName, [FromHeader(Name = "key")]string? KeyRaw) + public async Task Post([FromHeader(Name = "username")]string? UsernameRaw, [FromHeader(Name = "password")]string PasRaw, [FromHeader(Name = "displayname")]string? DisplayName, [FromHeader(Name = "key")]string? KeyRaw) { try { PictureType pfp; byte[] PasBytes, Username; - byte[] salt = new byte[100]; + byte[] salt = new byte[100], Body; + using (MemoryStream reader = new()) + { + await Request.Body.CopyToAsync(reader); + Body = reader.ToArray(); + } try { using (RandomNumberGenerator provider = RandomNumberGenerator.Create()) @@ -133,7 +198,7 @@ public class SocketAccountController : Controller } try { - PasBytes = Luski.Encryption.RemotePasswordEncrypt(Encryption.Generic.Encoders[(int)EncoderType.UTF16].GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(PasRaw), Luski.Encryption.Keys.PrivateKey)), salt); + PasBytes = Luski.Encryption.RemotePasswordEncrypt(PasRaw, salt); Username = Encryption.RSA.Decrypt(Convert.FromBase64String(UsernameRaw), Luski.Encryption.Keys.PrivateKey); try @@ -161,6 +226,11 @@ public class SocketAccountController : Controller int num = new Random().Next(1000, 1000000000); int num2 = new Random().Next(1000, 1000000000); Luski.Snowflake id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); + if (Tables.Server.Read(Server.Owner, Server.ID.CreateParameter(0)) == -1) + { + id = new(0); + Tables.Server.Update(Server.ID, 0, Server.Owner.CreateParameter(id.ID)); + } byte[] ID = Encoding.UTF8.GetBytes(id.ID.ToString()); byte[] Timestamp = Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString()); byte[] Number = Encoding.UTF8.GetBytes(num.ToString()); @@ -169,35 +239,24 @@ public class SocketAccountController : Controller pfp = GetProfilePictureType(Encoding.UTF8.GetString(Body).ToUpper()); long uid = id.ID; + long kid = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch).ID; Tables.Users.Insert( Users.ID.CreateParameter(uid), Users.DisplayName.CreateParameter(DisplayName!.Replace("'", "\'")), Users.SelectedChannel.CreateParameter(0), //TODO set to default channel - Users.Status.CreateParameter(Status.Offline), + Users.Status.CreateParameter(Status.Online), Users.PictureType.CreateParameter(pfp), Users.Picture.CreateParameter(Body), - Users.Roles.CreateParameter(Array.Empty()), + Users.Roles.CreateParameter(new long[] {0}), Users.Username.CreateParameter(Username), Users.Password.CreateParameter(PasBytes), - Users.Salt.CreateParameter(salt), - Users.OfflineData.CreateParameter(Array.Empty()), - Users.OffileKey.CreateParameter(0)); - id = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch); - long kid = id.ID; + Users.Salt.CreateParameter(salt)); 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)); + Thread t = new(o => RegToken((string?)o, kid)); t.Start(Token); return StatusCode(201, new Login() { @@ -254,15 +313,24 @@ public class SocketAccountController : Controller return true; } - private static void RegToken(string? token) + private static void RegToken(string? token, long kid) { try { if (token == null) return; long id = long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(token.Split('.')[0]))); - Tables.Sessions.Update(Sessions.ID, id, Sessions.LoginToken.CreateParameter(token)); + long l = Luski.Snowflake.GenerateSnowflake(Luski.Config.ServerEpoch).ID; + Tables.Sessions.Insert( + Sessions.ID.CreateParameter(l), + Sessions.User.CreateParameter(id), + Sessions.LoginToken.CreateParameter(token), + Sessions.SessionKey.CreateParameter(kid), + Sessions.WSSTCP.CreateParameter(string.Empty), + Sessions.Token.CreateParameter(string.Empty), + Sessions.StorageID.CreateParameter(0)); Thread.Sleep(30000); - Tables.Sessions.Update(Sessions.ID, id, Sessions.LoginToken.CreateParameter(string.Empty)); + if (Tables.Sessions.TryRead(Sessions.LoginToken, out string? tok, Sessions.ID.CreateParameter(l)) && tok == token) + Tables.Sessions.DeleteRow(Sessions.ID.CreateParameter(l)); } catch (Exception ex) { diff --git a/LuskiServer/Controllers/v1/SocketBulkMessageController.cs b/LuskiServer/Controllers/v1/SocketBulkMessageController.cs index 00ed585..565f27b 100644 --- a/LuskiServer/Controllers/v1/SocketBulkMessageController.cs +++ b/LuskiServer/Controllers/v1/SocketBulkMessageController.cs @@ -17,7 +17,7 @@ public class SocketBulkMessageController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; if (!Request.Headers.ContainsKey("id")) return this.ShowError(ErrorCode.MissingHeader, "You did not give an channel id for the channel you want to get a message from"); string channel_id = Request.Headers["id"].First(); long MessagesToDownload = 50; @@ -51,7 +51,7 @@ public class SocketBulkMessageController : ControllerBase } } SocketBulkMessage all = new(); - SocketMessage[]? mmm = null; + List mmmm = new List(); if (MostRecentID != null) { MessageRow[] rawmsgs = Tables.Messages.ReadRows((uint)MessagesToDownload, @@ -59,13 +59,13 @@ public class SocketBulkMessageController : ControllerBase Messages.TimeStamp.CreateParameter(new Luski.Snowflake(long.Parse(MostRecentID)).Timestamp, sign), Messages.ChannelID.CreateParameter(Channel_Id)); - List mmmm = new List(); + foreach (MessageRow Row in rawmsgs) { SocketMessage temp = new() { - content = Convert.ToBase64String(Row.Context), + context = Convert.ToBase64String(Row.Context), encoder_type = Row.EncoderType, encryption_key = Row.EncryptionKey, channel_id = Row.ChannelID, @@ -81,14 +81,14 @@ public class SocketBulkMessageController : ControllerBase 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 + encryption_key = fileraw.EncryptionKey, + channel = fileraw.Channel }; list.Add(file); } @@ -99,7 +99,7 @@ public class SocketBulkMessageController : ControllerBase } } - if (mmm is not null) all.messages = mmm; + if (mmmm is not null) all.messages = mmmm.ToArray(); else all.messages = Array.Empty(); return this.ResponseToResult(all); } diff --git a/LuskiServer/Controllers/v1/SocketCategoryController.cs b/LuskiServer/Controllers/v1/SocketCategoryController.cs new file mode 100644 index 0000000..bc4cdc9 --- /dev/null +++ b/LuskiServer/Controllers/v1/SocketCategoryController.cs @@ -0,0 +1,140 @@ +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; +using Microsoft.CodeAnalysis; + +namespace LuskiServer.Controllers.v1; + +[ApiVersion(1)] +[ApiController] +public class SocketCategoryController : ControllerBase +{ + [HttpPost] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Post([FromBody]UserChannelRequest ChanReq) + { + try + { + if (!this.CanTokenRequest(out long ID, out long SID, 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.EncryptionKeys.CreateParameter(ChanReq.encryption_keys), + 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 long SID, 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) + { + try + { + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; + if (!Luski.HasAccessToCategory(ID, Channel, out IReadOnlyList opt, ServerPermissions.ViewCategories, ServerPermissions.ViewChannels)) return this.ResponseCodeToResult(ErrorCode.Forbidden); + var chan = Tables.Categories.ReadRow(Categories.ID.CreateParameter(Channel)); + if (opt.Contains(ServerPermissions.ViewCategories)) + { + chan.InnerCategories = Array.Empty(); + } + if (opt.Contains(ServerPermissions.ViewChannels)) + { + chan.Channels = Array.Empty(); + } + return this.ResponseToResult(new UserCategoryResponse() + { + name = Convert.ToBase64String(chan.Name), + description = Convert.ToBase64String(chan.Description), + id = Channel, + channels = chan.Channels, + inner_categories = chan.InnerCategories, + parent = chan.Parent, + title_encryption_key = chan.TitleEncryptionKey, + description_encryption_key = chan.DescriptionEncryptionKey, + title_encoder_type = chan.TitleEncoderType, + description_encoder_type = chan.DescriptionEncoderType, + member_overides = chan.UserOverides, + role_overides = chan.RoleOverides, + color = chan.Color + }); + } + catch (Exception e) + { + return this.ShowError(e); + } + } +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketChannelController.cs b/LuskiServer/Controllers/v1/SocketChannelController.cs index ebb8855..8d45c46 100644 --- a/LuskiServer/Controllers/v1/SocketChannelController.cs +++ b/LuskiServer/Controllers/v1/SocketChannelController.cs @@ -1,3 +1,4 @@ +using System.Text; using Asp.Versioning; using LuskiServer.Classes; using LuskiServer.Classes.TableDef; @@ -18,7 +19,7 @@ public class SocketChannelController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, 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(); @@ -60,9 +61,7 @@ public class SocketChannelController : ControllerBase 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.EncryptionKeys.CreateParameter(ChanReq.encryption_keys), Channels.TitleEncoderType.CreateParameter(ChanReq.title_encoder_type), Channels.DescriptionEncoderType.CreateParameter(ChanReq.description_encoder_type), Channels.EncoderTypes.CreateParameter(ChanReq.encoder_types)); @@ -80,7 +79,7 @@ public class SocketChannelController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, 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)); @@ -100,17 +99,45 @@ public class SocketChannelController : ControllerBase } [HttpGet] - [Route(Luski.Info.Routes.Default.Base)] - public IActionResult Get([FromHeader(Name = "id")]long Channel) //TODO add channel get + [Route(Luski.Info.Routes.Default.Base + "/GetPicture")] + public IActionResult GetPicture([FromHeader(Name = "id")]long chan) { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; + if (!Luski.HasAccessToChannel(ID, chan)) return this.ResponseCodeToResult(ErrorCode.Forbidden); + if (!Tables.Channels.TryRead(Channels.Picture, out byte[] image, Channels.ID.CreateParameter(chan))) return this.ResponseCodeToResult(ErrorCode.Forbidden); + return Tables.Channels.Read(Channels.PictureType, Channels.ID.CreateParameter(chan)) switch + { + PictureType.png => File(image, "image/png"), + PictureType.jpeg => File(image, "image/jpeg"), + PictureType.bmp => File(image, "image/bmp"), + PictureType.gif => File(image, "image/gif"), + PictureType.ico => File(image, "image/vnd.microsoft.icon"), + PictureType.svg => File(image, "image/svg+xml"), + PictureType.tif => File(image, "image/tiff"), + PictureType.webp => File(image, "image/webp"), + _ => File(image, "image/png"), + }; + } + catch (Exception e) + { + return this.ShowError(e); + } + } + + [HttpGet] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromHeader(Name = "id")]long Channel) + { + try + { + if (!this.CanTokenRequest(out long ID, out long SID, 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), + name = Convert.ToBase64String(chan.Name), description = Convert.ToBase64String(chan.Description), id = Channel, type = chan.Type, @@ -118,12 +145,14 @@ public class SocketChannelController : ControllerBase 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, + encryption_keys = chan.EncryptionKeys, title_encoder_type = chan.TitleEncoderType, description_encoder_type = chan.DescriptionEncoderType, - encoder_types = chan.EncoderTypes + encoder_types = chan.EncoderTypes, + member_overides = chan.UserOverides, + role_overides = chan.RoleOverides, + picture_type = chan.PictureType, + color = chan.Color }); } catch (Exception e) diff --git a/LuskiServer/Controllers/v1/SocketFileController.cs b/LuskiServer/Controllers/v1/SocketFileController.cs index 5b7e2dd..a235399 100644 --- a/LuskiServer/Controllers/v1/SocketFileController.cs +++ b/LuskiServer/Controllers/v1/SocketFileController.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.SymbolStore; using System.Net.Mime; using System.Text; using Asp.Versioning; @@ -17,28 +18,41 @@ 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) + public IActionResult Get([FromQuery(Name = "id")]long id, [FromQuery(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); + if (!Tables.Files.TryRead(Files.Data, out byte[] raw, Files.ID.CreateParameter(id))) return this.ResponseCodeToResult(ErrorCode.Forbidden); + if (Tables.Files.Read(Files.Public, Files.ID.CreateParameter(id))) + { + FileRow r = Tables.Files.ReadRow(Files.ID.CreateParameter(id)); + if (r.EncryptionKey == 0) + { + return File(raw, MediaTypeNames.Application.Octet, Encryption.Generic.Encoders[(int)r.NameEncoderType].GetString(r.Name)); + } + else return File(raw, MediaTypeNames.Application.Octet); + } + else + { + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; + if (!Channel_id.HasValue) return this.ResponseCodeToResult(ErrorCode.InvalidURL); + if (!Luski.HasAccessToChannel(ID, Channel_id.Value, 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 (!this.CanTokenRequest(out long ID, out long SID, 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()), @@ -61,7 +75,7 @@ public class SocketFileController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, 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))) diff --git a/LuskiServer/Controllers/v1/SocketMessageController.cs b/LuskiServer/Controllers/v1/SocketMessageController.cs index 8e0a5e2..2ae571a 100644 --- a/LuskiServer/Controllers/v1/SocketMessageController.cs +++ b/LuskiServer/Controllers/v1/SocketMessageController.cs @@ -23,14 +23,14 @@ public class SocketMessageController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; 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), + context = Convert.ToBase64String(msgraw.Context), id = MSG_id, channel_id = Channel_Id }; @@ -42,7 +42,6 @@ public class SocketMessageController : ControllerBase 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()), @@ -73,7 +72,7 @@ public class SocketMessageController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, 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)); diff --git a/LuskiServer/Controllers/v1/SocketRoleController.cs b/LuskiServer/Controllers/v1/SocketRoleController.cs new file mode 100644 index 0000000..ceaebf2 --- /dev/null +++ b/LuskiServer/Controllers/v1/SocketRoleController.cs @@ -0,0 +1,32 @@ +using Asp.Versioning; +using LuskiServer.Classes; +using LuskiServer.Classes.TableDef; +using LuskiServer.Classes.WebTypes; +using LuskiServer.Enums; +using Microsoft.AspNetCore.Mvc; + +namespace LuskiServer.Controllers.v1; + +[ApiVersion(1)] +[ApiController] +public class SocketRoleController : ControllerBase +{ + [HttpGet] + [Route(Luski.Info.Routes.Default.Base)] + public IActionResult Get([FromQuery(Name = "id")]long id) + { + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; + if (!Tables.Roles.TryReadRow(out RoleRow row, Roles.ID.CreateParameter(id))) return this.ShowError(ErrorCode.Forbidden, "User does not exist"); + return this.ResponseToResult(new Role() + { + id = row.ID, + server_permissions = row.ServerPermissions, + description = row.Description, + display_name = row.DisplayName, + index = row.Index, + name = row.Name, + members_list = row.MembersList, + color = row.Color + }); + } +} \ No newline at end of file diff --git a/LuskiServer/Controllers/v1/SocketServerController.cs b/LuskiServer/Controllers/v1/SocketServerController.cs index 9cf94c9..a8759e9 100644 --- a/LuskiServer/Controllers/v1/SocketServerController.cs +++ b/LuskiServer/Controllers/v1/SocketServerController.cs @@ -25,6 +25,7 @@ public class SocketServerController : ControllerBase var sr = Tables.Server.ReadRow(Server.ID.CreateParameter(0)); return this.ResponseToResult(new ServerInfoJson() { + wssv4 = (Luski.Config.IPv4_Overode_WSS is null ? $"{(Luski.Config.IPv4SecureWSS ? "wss" : "ws" )}://{Luski.Config.IPv4WSS}:{Luski.Config.IPv4PortWSS}{Luski.Config.IPv4_URL_WSS}v1" : Luski.Config.IPv4_Overode_WSS + "v1"), name = sr.Name, description = sr.Description, owner = sr.Owner diff --git a/LuskiServer/Controllers/v1/SocketUserController.cs b/LuskiServer/Controllers/v1/SocketUserController.cs index dfe5bc0..f715602 100644 --- a/LuskiServer/Controllers/v1/SocketUserController.cs +++ b/LuskiServer/Controllers/v1/SocketUserController.cs @@ -18,7 +18,7 @@ public class SocketUserController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, 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() { diff --git a/LuskiServer/Controllers/v1/SocketUserProfileController.cs b/LuskiServer/Controllers/v1/SocketUserProfileController.cs index 01e0834..6788854 100644 --- a/LuskiServer/Controllers/v1/SocketUserProfileController.cs +++ b/LuskiServer/Controllers/v1/SocketUserProfileController.cs @@ -92,7 +92,7 @@ public class SocketUserProfileController : ControllerBase { try { - if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc; + if (!this.CanTokenRequest(out long ID, out long SID, out IActionResult? toc) && toc != null) return toc; //dynamic? SentData = Newtonsoft.Json.JsonConvert.DeserializeObject(content); Status NewStatus = SentData.status; diff --git a/LuskiServer/Converters/Matrix/Matrix.cs b/LuskiServer/Converters/Matrix/Matrix.cs new file mode 100644 index 0000000..3b7734b --- /dev/null +++ b/LuskiServer/Converters/Matrix/Matrix.cs @@ -0,0 +1,160 @@ +using System.IO.Compression; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using JacobTechEncryption.Enums; +using LuskiServer.Classes; +using LuskiServer.Classes.TableDef; +using LuskiServer.Converters.Matrix.Types; +using LuskiServer.Enums; + +namespace LuskiServer.Converters.Matrix; + +public static class Matrix +{ + public static void ZipJsonChatExpot(Stream Zip, long Channel, Dictionary UserMap, + List IgnoredUsers, EncoderType Encoder, long Encryption, bool remove = true) + { + if (Tables.Channels.TryRead(Channels.ID, out _, Channels.ID.CreateParameter(Channel))) + { + Tables.Messages.DeleteRow(Messages.ChannelID.CreateParameter(Channel)); + Tables.Files.DeleteRow(Files.Channel.CreateParameter(Channel)); + //throw new Exception("Channel Exist"); + } + + using ZipArchive archive = new ZipArchive(Zip, ZipArchiveMode.Read, false); + string internalfolder = archive.Entries[0].FullName; + ZipArchiveEntry json = archive.GetEntry(internalfolder + "export.json")!; + MessageExport export = JsonSerializer.Deserialize(json.Open(), MessageExportContext.Default.MessageExport)!; + + DateTime epoch = DateTime.UnixEpoch.AddMilliseconds(export.Messages[0].Origin).Date; + + try + { + Tables.Channels.Update(Channels.ID, Channel, + //Tables.Channels.Insert( + Channels.ID.CreateParameter(Channel), + Channels.Parent.CreateParameter(0), + Channels.Type.CreateParameter(ChannelType.TextAndVoice), + Channels.Description.CreateParameter(export.RoomTopic.ToDB(Encoder, Encryption)), + Channels.Name.CreateParameter(export.RoomName.ToDB(Encoder, Encryption)), + Channels.RoleOverides.CreateParameter(Array.Empty()), + Channels.UserOverides.CreateParameter(Array.Empty()), + Channels.Epoch.CreateParameter(epoch), + Channels.TitleEncryptionKey.CreateParameter(Encryption), + Channels.DescriptionEncryptionKey.CreateParameter(Encryption), + Channels.EncryptionKeys.CreateParameter(new long[] { Encryption }), + Channels.TitleEncoderType.CreateParameter(Encoder), + Channels.DescriptionEncoderType.CreateParameter(Encoder), + //Channels.PictureType.CreateParameter(PictureType.none), + //Channels.Picture.CreateParameter(Array.Empty()), + Channels.EncoderTypes.CreateParameter(new[] { Encoder })); + + + foreach (Message msg in export.Messages) + { + if (msg.Type != "m.room.message") + continue; + if (!UserMap.ContainsKey(msg.Sender)) + { + if (IgnoredUsers.Contains(msg.Sender)) + continue; + if (remove) + { + Tables.Messages.DeleteRow(Messages.ChannelID.CreateParameter(Channel)); + Tables.Files.DeleteRow(Files.Channel.CreateParameter(Channel)); + } + + throw new Exception($"User not in list: {msg.Sender}"); + } + + DateTime cur = DateTime.UnixEpoch.AddMilliseconds(msg.Origin); + if (msg.Context.Type is null) + continue; + Luski.Snowflake sf = Luski.Snowflake.GenerateSnowflake(epoch, cur); + cur = cur.ToLocalTime(); + switch (msg.Context.Type) + { + default: + + Tables.Messages.Insert( + Messages.ID.CreateParameter(sf.ID), + Messages.Context.CreateParameter(msg.Context.Body.ToDB(Encoder, Encryption)), + Messages.ChannelID.CreateParameter(Channel), + Messages.EncoderType.CreateParameter(Encoder), + Messages.Files.CreateParameter(Array.Empty()), + Messages.EncryptionKey.CreateParameter(Encryption), + Messages.TimeStamp.CreateParameter(sf.Timestamp), + Messages.AuthorID.CreateParameter(UserMap[msg.Sender])); + break; + case "m.image" or "m.video" or "m.audio" or "m.file": + int h = cur.Hour; + string pm = "AM"; + if (h > 11) + { + h = h - 12; + if (h == 0) h = 12; + pm = "PM"; + } + + string hh = h.ToString(); + string mm = cur.Minute.ToString(); + string s = cur.Second.ToString(); + if (s.Length == 1) s = "0" + s; + if (mm.Length == 1) mm = "0" + mm; + if (hh.Length == 1) hh = "0" + hh; + string[] spl = msg.Context.Body.Split('.'); + string fil = + $"{spl[0]}-{cur.Month}-{cur.Day}-{cur.Year} at {h}-{mm}-{s} {pm}.{spl[spl.Length - 1]}"; + string loc = msg.Context.Type.Split('.')[1] + "s"; + if (loc == "audios") loc = "audio"; + if (fil.EndsWith(".1")) fil = fil.Remove(fil.Length - 2, 2); + ZipArchiveEntry? f; + if ((f = archive.GetEntry(internalfolder + loc + "/" + fil)) is not null) + { + byte[] d; + using(var memoryStream = new MemoryStream()) + { + f.Open().CopyTo(memoryStream); + d = memoryStream.ToArray(); + } + + Tables.Files.Insert( + Files.ID.CreateParameter(sf.ID), + Files.Name.CreateParameter(msg.Context.Body.ToDB(Encoder, Encryption)), + Files.Data.CreateParameter(d), + Files.EncoderType.CreateParameter(Encoder), + Files.EncryptionKey.CreateParameter(Encryption), + Files.Hash.CreateParameter(JacobTechEncryption.Encryption.Hashing.SHA256(d)), + Files.Owner.CreateParameter(UserMap[msg.Sender]), + Files.AllowedChannels.CreateParameter(new long[] { Channel }), + Files.Public.CreateParameter(true), + Files.Size.CreateParameter(d.LongLength), + Files.NameEncoderType.CreateParameter(Encoder), + Files.NameEncryptionKey.CreateParameter(Encryption)); + Tables.Messages.Insert( + Messages.ID.CreateParameter(sf.ID), + Messages.Context.CreateParameter(Array.Empty()), + Messages.ChannelID.CreateParameter(Encryption), + Messages.EncoderType.CreateParameter(Encoder), + Messages.Files.CreateParameter(new[] { sf.ID }), + Messages.EncryptionKey.CreateParameter(Encryption), + Messages.TimeStamp.CreateParameter(sf.Timestamp), + Messages.AuthorID.CreateParameter(UserMap[msg.Sender])); + } + break; + } + } + } + catch (Exception e) + { + Console.WriteLine(e); + if (remove) + { + Tables.Messages.DeleteRow(Messages.ChannelID.CreateParameter(Channel)); + Tables.Files.DeleteRow(Files.Channel.CreateParameter(Channel)); + } + throw; + } + } +} \ No newline at end of file diff --git a/LuskiServer/Converters/Matrix/Types/Message.cs b/LuskiServer/Converters/Matrix/Types/Message.cs new file mode 100644 index 0000000..1c7bfa4 --- /dev/null +++ b/LuskiServer/Converters/Matrix/Types/Message.cs @@ -0,0 +1,45 @@ +using System.Text.Json.Serialization; + +namespace LuskiServer.Converters.Matrix.Types; + +public class Message +{ + [JsonInclude] + [JsonPropertyName("content")] + public MessageContext Context { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("origin_server_ts")] + public long Origin { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("room_id")] + public string Room { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("sender")] + public string Sender { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("state_key")] + public string State { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("type")] + public string Type { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("event_id")] + public string Event { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("user_id")] + public string Author { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("age")] + public long TimeStamp { get; set; } = default!; + + [JsonInclude] + [JsonPropertyName("unsigned")] + public Unsigned Unsigned { get; set; } = default!; +} + +[JsonSerializable(typeof(Message))] +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.Never, GenerationMode = JsonSourceGenerationMode.Default)] +internal partial class MessageJsonContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/LuskiServer/Converters/Matrix/Types/MessageContext.cs b/LuskiServer/Converters/Matrix/Types/MessageContext.cs new file mode 100644 index 0000000..7cf1d16 --- /dev/null +++ b/LuskiServer/Converters/Matrix/Types/MessageContext.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace LuskiServer.Converters.Matrix.Types; + +public class MessageContext +{ + [JsonInclude] + [JsonPropertyName("body")] + public string Body { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("msgtype")] + public string Type { get; set; } = default!; +} \ No newline at end of file diff --git a/LuskiServer/Converters/Matrix/Types/MessageExport.cs b/LuskiServer/Converters/Matrix/Types/MessageExport.cs new file mode 100644 index 0000000..c0e894a --- /dev/null +++ b/LuskiServer/Converters/Matrix/Types/MessageExport.cs @@ -0,0 +1,32 @@ +using System.Text.Json.Serialization; + +namespace LuskiServer.Converters.Matrix.Types; + +public class MessageExport +{ + [JsonInclude] + [JsonPropertyName("room_name")] + public string RoomName { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("room_creator")] + public string RoomOwner { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("topic")] + public string RoomTopic { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("export_date")] + public string ExportDate { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("exported_by")] + public string Exporter { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("messages")] + public Message[] Messages { get; set; } = default!; +} + +[JsonSerializable(typeof(MessageExport))] +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.Never, GenerationMode = JsonSourceGenerationMode.Default)] +internal partial class MessageExportContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/LuskiServer/Converters/Matrix/Types/Unsigned.cs b/LuskiServer/Converters/Matrix/Types/Unsigned.cs new file mode 100644 index 0000000..b22eca0 --- /dev/null +++ b/LuskiServer/Converters/Matrix/Types/Unsigned.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace LuskiServer.Converters.Matrix.Types; + +public class Unsigned +{ + [JsonInclude] + [JsonPropertyName("age")] + public long Age { get; set; } = default!; +} \ No newline at end of file diff --git a/LuskiServer/Enums/PictureType.cs b/LuskiServer/Enums/PictureType.cs index 93b65be..ab12e98 100644 --- a/LuskiServer/Enums/PictureType.cs +++ b/LuskiServer/Enums/PictureType.cs @@ -2,6 +2,7 @@ namespace LuskiServer.Enums; public enum PictureType : short { + none, png, jpeg, bmp, diff --git a/LuskiServer/Enums/ServerComs/DataType.cs b/LuskiServer/Enums/ServerComs/DataType.cs index a02e3f7..bf3f206 100644 --- a/LuskiServer/Enums/ServerComs/DataType.cs +++ b/LuskiServer/Enums/ServerComs/DataType.cs @@ -2,5 +2,6 @@ namespace LuskiServer.Enums.ServerComs; public enum DataType { + Token, MessageCreate } \ No newline at end of file diff --git a/LuskiServer/Enums/ServerComs/SendType.cs b/LuskiServer/Enums/ServerComs/SendType.cs index 623df93..32b0fc4 100644 --- a/LuskiServer/Enums/ServerComs/SendType.cs +++ b/LuskiServer/Enums/ServerComs/SendType.cs @@ -2,6 +2,8 @@ namespace LuskiServer.Enums.ServerComs; public enum SendType { + Self, + Client, All, ID_Group, ID diff --git a/LuskiServer/Enums/ServerPermissions.cs b/LuskiServer/Enums/ServerPermissions.cs index 7a664a1..3992894 100644 --- a/LuskiServer/Enums/ServerPermissions.cs +++ b/LuskiServer/Enums/ServerPermissions.cs @@ -2,6 +2,7 @@ namespace LuskiServer.Enums; public enum ServerPermissions : long { + ViewThis, ViewChannels, MoveChannels, EditChannels, diff --git a/LuskiServer/LuskiServer.csproj b/LuskiServer/LuskiServer.csproj index 9d3da0d..fd8fe7e 100644 --- a/LuskiServer/LuskiServer.csproj +++ b/LuskiServer/LuskiServer.csproj @@ -20,13 +20,14 @@ - + - + + diff --git a/LuskiServer/Program.cs b/LuskiServer/Program.cs index 8a026c5..1a73f78 100644 --- a/LuskiServer/Program.cs +++ b/LuskiServer/Program.cs @@ -1,10 +1,15 @@ using System.Reflection; +using System.Runtime.InteropServices.JavaScript; using System.Text; using Asp.Versioning.ApiExplorer; +using JacobTechEncryption; using JacobTechEncryption.Enums; using LuskiServer; using LuskiServer.Classes; +using LuskiServer.Classes.ServerComs; using LuskiServer.Classes.TableDef; +using LuskiServer.Converters.Matrix; +using LuskiServer.Converters.Matrix.Types; using LuskiServer.Enums; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; @@ -22,6 +27,23 @@ Luski.Database = new Database(Luski.Config.Address, Luski.Config.Password, Luski.Config.CustomeName); +DirectoryInfo di = + new("/home/jacob/Downloads/matrix - Luski Project Discussion - Chat Export - 2023-08-08T01-13-19.480Z"); +foreach (DirectoryInfo d in di.GetDirectories()) +{ + foreach (FileInfo file in d.GetFiles()) + { + // Tables.Files.Insert( + // Files.ID.CreateParameter(0), + // Files.EncoderType.CreateParameter(EncoderType.UTF8), + // Files.Name); + } +} + + +Dictionary> fff = new(); + + try { Luski.Database.ExecuteNonQuery($"CREATE DATABASE {Luski.Config.Database} WITH OWNER = {Luski.Config.Username} ENCODING = 'UTF8' CONNECTION LIMIT = -1 IS_TEMPLATE = False;"); @@ -46,22 +68,148 @@ foreach (PropertyInfo prop in typeof(Tables).GetProperties()) Luski.Database.RegisterTables(); +Dictionary AMap = new() +{ + {"@jacobtech:matrix.org", 0}, + {"@rqndomnezz:matrix.org", 0}, + {"@ardillybar:matrix.org", 0}, + {"@themagicalcats:matrix.org", 0}, + {"@jobotnik:matrix.org", 0}, + {"@captainleader:matrix.org", 0}, + {"@kaizenash:matrix.org", 0}, + {"@bubs_cooper:matrix.org", 0}, + {"@quadro:matrix.org", 0}, + {"@tcll:matrix.org", 0}, + {"@eeetile:matrix.org", 0}, + {"@etile:matrix.org", 0}, + {"@tranquillity_:midov.pl", 0} +}; +//Matrix.ZipJsonChatExpot(File.OpenRead("/home/jacob/Downloads/matrix - Luski Project Discussion - Chat Export - 2023-08-08T20-10-12.315Z.zip"), 0, AMap, new(), EncoderType.UTF16, 0); + if (!Tables.Server.TryRead(Server.ID, out _, Server.ID.CreateParameter(0))) { Tables.Server.Insert(); } - +//Tables.Server.Update(Server.ID, 0, Server.Picture.CreateParameter(File.ReadAllBytes("/home/jacob/Downloads/XBsECOXDZIXMVIxxMNxRfGRo.png"))); +//Tables.Channels.Update(Channels.ID, 1, Channels.PictureType.CreateParameter(PictureType.png), Channels.Picture.CreateParameter(File.ReadAllBytes("/home/jacob/Downloads/zLqHooejmsmKzuMLneUSvjRH.png"))); +/* +Tables.Channels.Insert( + Channels.ID.CreateParameter(1), + Channels.Parent.CreateParameter(0), + Channels.Type.CreateParameter(ChannelType.TextAndVoice), + Channels.Description.CreateParameter(Encoding.UTF8.GetBytes("A nother test Chat")), + Channels.Name.CreateParameter(Encoding.UTF8.GetBytes("Chat 1")), + Channels.RoleOverides.CreateParameter(Array.Empty()), + Channels.UserOverides.CreateParameter(Array.Empty()), + Channels.Epoch.CreateParameter(DateTime.UtcNow.Date), + Channels.TitleEncryptionKey.CreateParameter(0), + Channels.DescriptionEncryptionKey.CreateParameter(0), + Channels.EncryptionKeys.CreateParameter(new long[]{0}), + Channels.TitleEncoderType.CreateParameter(EncoderType.UTF8), + Channels.DescriptionEncoderType.CreateParameter(EncoderType.UTF8), + Channels.PictureType.CreateParameter(PictureType.png), + Channels.Picture.CreateParameter(File.ReadAllBytes("/home/jacob/Downloads/4ba.png")), + Channels.EncoderTypes.CreateParameter(new [] { EncoderType.UTF8 })); +Tables.Channels.Insert( + Channels.ID.CreateParameter(2), + Channels.Parent.CreateParameter(1), + Channels.Type.CreateParameter(ChannelType.TextAndVoice), + Channels.Description.CreateParameter(Encoding.UTF8.GetBytes("A nother test Chat")), + Channels.Name.CreateParameter(Encoding.UTF8.GetBytes("Chat 2")), + Channels.RoleOverides.CreateParameter(Array.Empty()), + Channels.UserOverides.CreateParameter(Array.Empty()), + Channels.Epoch.CreateParameter(DateTime.UtcNow.Date), + Channels.TitleEncryptionKey.CreateParameter(0), + Channels.DescriptionEncryptionKey.CreateParameter(0), + Channels.EncryptionKeys.CreateParameter(new long[]{0}), + Channels.TitleEncoderType.CreateParameter(EncoderType.UTF8), + Channels.DescriptionEncoderType.CreateParameter(EncoderType.UTF8), + Channels.PictureType.CreateParameter(PictureType.png), + Channels.Picture.CreateParameter(File.ReadAllBytes("/home/jacob/Downloads/4ba.png")), + Channels.EncoderTypes.CreateParameter(new [] { EncoderType.UTF8 })); +Tables.Channels.Insert( + Channels.ID.CreateParameter(3), + Channels.Parent.CreateParameter(2), + Channels.Type.CreateParameter(ChannelType.TextAndVoice), + Channels.Description.CreateParameter(Encoding.UTF8.GetBytes("A nother test Chat")), + Channels.Name.CreateParameter(Encoding.UTF8.GetBytes("Chat 3")), + Channels.RoleOverides.CreateParameter(Array.Empty()), + Channels.UserOverides.CreateParameter(Array.Empty()), + Channels.Epoch.CreateParameter(DateTime.UtcNow.Date), + Channels.TitleEncryptionKey.CreateParameter(0), + Channels.DescriptionEncryptionKey.CreateParameter(0), + Channels.EncryptionKeys.CreateParameter(new long[]{0}), + Channels.TitleEncoderType.CreateParameter(EncoderType.UTF8), + Channels.DescriptionEncoderType.CreateParameter(EncoderType.UTF8), + Channels.PictureType.CreateParameter(PictureType.png), + Channels.Picture.CreateParameter(File.ReadAllBytes("/home/jacob/Downloads/4ba.png")), + Channels.EncoderTypes.CreateParameter(new [] { EncoderType.UTF8 })); +Tables.Categories.Insert( + Categories.ID.CreateParameter(1), + Categories.Name.CreateParameter(Encoding.UTF8.GetBytes("Cat lol")), + Categories.Parent.CreateParameter(0), + Categories.Description.CreateParameter( + Encoding.UTF8.GetBytes("Test cat")), + Categories.RoleOverides.CreateParameter(Array.Empty()) +); +Tables.Categories.Insert( + Categories.ID.CreateParameter(2), + Categories.Name.CreateParameter(Encoding.UTF8.GetBytes("Cat lol")), + Categories.Parent.CreateParameter(1), + Categories.Description.CreateParameter( + Encoding.UTF8.GetBytes("Test cat")), + Categories.RoleOverides.CreateParameter(Array.Empty()) +); +*/ if (!Luski.Database.VersionsTable.TryRead(Luski.Database.VersionsTable.ID, out _, Luski.Database.VersionsTable.ID.CreateParameter(0))) { Luski.Database.VersionsTable.Insert(Luski.Database.VersionsTable.ID.CreateParameter(0)); } +/* +Tables.Roles.Insert( + Roles.ID.CreateParameter(1), + Roles.Name.CreateParameter("Mod"), + Roles.DisplayName.CreateParameter("Moderators"), + Roles.Color.CreateParameter("56,155,32,255"), + Roles.Description.CreateParameter("Mods for the server"), + Roles.ServerPermissions.CreateParameter(new[] + { + ServerPermissions.ViewChannels, + ServerPermissions.ViewCategories, + ServerPermissions.Nickname, + ServerPermissions.SendMessages, + ServerPermissions.SendFiles, + ServerPermissions.ChannelAndServerPings, + ServerPermissions.PingSomeone, + ServerPermissions.ReadMessageHistory, + ServerPermissions.UseServerCommands, + ServerPermissions.JoinVoice, + ServerPermissions.SpeakInVoice, + ServerPermissions.ViewThis, + ServerPermissions.Kick, + ServerPermissions.CreateCategories, + ServerPermissions.CreateChannels, + ServerPermissions.DeleteCategories, + ServerPermissions.DeleteChannels, + ServerPermissions.EditCategories, + ServerPermissions.EditChannels, + ServerPermissions.EditCategoryPermissions, + ServerPermissions.EditChannelPermissions, + ServerPermissions.Invite, + ServerPermissions.ManageMessages, + ServerPermissions.ManageRoles, + ServerPermissions.ViewLogs + }) +); +*/ if (!Tables.Roles.TryRead(Roles.ID, out _, Roles.ID.CreateParameter(0))) { Tables.Roles.Insert( Roles.ID.CreateParameter(0), Roles.Name.CreateParameter("server"), + Roles.DisplayName.CreateParameter("Members"), Roles.Color.CreateParameter("5,5,5,5"), Roles.Description.CreateParameter("The default role for the server. Everybody will have this role."), Roles.ServerPermissions.CreateParameter(new[] @@ -76,7 +224,8 @@ if (!Tables.Roles.TryRead(Roles.ID, out _, Roles.ID.CreateParameter(0))) ServerPermissions.ReadMessageHistory, ServerPermissions.UseServerCommands, ServerPermissions.JoinVoice, - ServerPermissions.SpeakInVoice + ServerPermissions.SpeakInVoice, + ServerPermissions.ViewThis }) ); } @@ -97,7 +246,7 @@ if (!Tables.Categories.TryRead(Categories.ID, out _, Categories.ID.CreateParamet Categories.Parent.CreateParameter(-1), Categories.Description.CreateParameter( Encoding.UTF8.GetBytes("The default category for the server. Everybody will see this category.")), - Categories.RoleOverides.CreateParameter(new long[1] { 0 }) + Categories.RoleOverides.CreateParameter(Array.Empty()) ); Tables.Channels.Insert( Channels.ID.CreateParameter(0), @@ -108,15 +257,20 @@ if (!Tables.Categories.TryRead(Categories.ID, out _, Categories.ID.CreateParamet Channels.UserOverides.CreateParameter(Array.Empty()), Channels.Epoch.CreateParameter(DateTime.UtcNow.Date), Channels.TitleEncryptionKey.CreateParameter(0), + Channels.Parent.CreateParameter(0), Channels.DescriptionEncryptionKey.CreateParameter(0), - Channels.EncoderBlacklist.CreateParameter(true), - Channels.EncryptionBlacklist.CreateParameter(true), - Channels.EncryptionTypes.CreateParameter(Array.Empty()), + Channels.EncryptionKeys.CreateParameter(new long[]{0}), Channels.TitleEncoderType.CreateParameter(EncoderType.UTF8), Channels.DescriptionEncoderType.CreateParameter(EncoderType.UTF8), - Channels.EncoderTypes.CreateParameter(Array.Empty())); + Channels.PictureType.CreateParameter(PictureType.none), + Channels.Picture.CreateParameter(Array.Empty()), + Channels.EncoderTypes.CreateParameter(new [] { EncoderType.UTF8 })); } +Tables.Sessions.DeleteRows(); + +WSS.Init(Luski.Config.IPv4WSS, Luski.Config.IPv4PortWSS, Luski.Config.IPv4_URL_WSS!, Luski.Config.IPv4SecureWSS, Luski.Config.IPv6WSS, Luski.Config.IPv6_URL_WSS, Luski.Config.IPv6PortWSS, Luski.Config.IPv6SecureWSS); + var builder = WebApplication.CreateBuilder( args ); // Add services to the container. @@ -194,11 +348,11 @@ builder.Services.AddSwaggerGen( options.IncludeXmlComments(filePath, true); } ); -var app = builder.Build(); - +WebApplication app = builder.Build(); // Configure the HTTP request pipeline. app.UseSwagger(); +//app.UseHttpLogging(); app.UseSwaggerUI( options => { diff --git a/LuskiServer/Properties/launchSettings.json b/LuskiServer/Properties/launchSettings.json index 0623b73..a3e8c21 100644 --- a/LuskiServer/Properties/launchSettings.json +++ b/LuskiServer/Properties/launchSettings.json @@ -12,9 +12,9 @@ "http": { "commandName": "Project", "dotnetRunMessages": true, - "launchBrowser": true, + "launchBrowser": false, "launchUrl": "swagger", - "applicationUrl": "http://localhost:5288;http://10.100.0.10:5287", + "applicationUrl": "http://localhost:5288;http://localhost:5287", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -24,7 +24,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7173;http://10.100.0.10:5287", + "applicationUrl": "https://localhost:7173;http:/localhost:5287", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/LuskiServer/appsettings.Development.json b/LuskiServer/appsettings.Development.json index 10f68b8..bb20fb6 100644 --- a/LuskiServer/appsettings.Development.json +++ b/LuskiServer/appsettings.Development.json @@ -2,7 +2,8 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" } }, "AllowedHosts": "*" diff --git a/LuskiServer/appsettings.json b/LuskiServer/appsettings.json index 10f68b8..bb20fb6 100644 --- a/LuskiServer/appsettings.json +++ b/LuskiServer/appsettings.json @@ -2,7 +2,8 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" } }, "AllowedHosts": "*"