diff --git a/Luski.net/API.cs b/Luski.net/API.cs index ec74a72..0a26552 100644 --- a/Luski.net/API.cs +++ b/Luski.net/API.cs @@ -33,6 +33,9 @@ public class API internal List InternalServers { get; } = new(); public IReadOnlyList LoadedServers => InternalServers.AsReadOnly(); + internal List InternalFailedServers { get; } = new(); + public IReadOnlyList FailedServers => InternalFailedServers.AsReadOnly(); + private static HttpResponseMessage GetFromServer(string Domain, string ApiVersion, bool Secure, string Path, CancellationToken CancellationToken, params KeyValuePair[] Headers) { using HttpClient web = new(); @@ -107,7 +110,7 @@ public class API { IEnumerable isl = InternalServers.Where(a => (a.Domain == Domain && a.ApiVersion == Version)); if (isl.Any()) return isl.First(); - s = await PublicServer.GetServer(Domain, Version, Secure, GenerateEncryption, LogConsole); + s = await PublicServer.GetServer(InternalFailedServers, Domain, Version, Secure, GenerateEncryption, LogConsole); } catch (Exception e) { diff --git a/Luski.net/Interfaces/IUser.cs b/Luski.net/Interfaces/IUser.cs index 68d4de9..bd17814 100755 --- a/Luski.net/Interfaces/IUser.cs +++ b/Luski.net/Interfaces/IUser.cs @@ -17,26 +17,9 @@ public interface IUser /// long Id { get; } /// - /// The cerrent username of the user - /// - string DisplayName { get; } - /// /// The current status of the user /// UserStatus Status { get; } - - /// - /// The color of the display name - /// - Task GetColor(); - /// - /// will returen the picture type of the user - /// - PictureType PictureType { get; } - /// - /// Gets the current avatar of the user - /// - Task GetAvatar(CancellationToken CancellationToken); /// /// Gets the current user keys /// diff --git a/Luski.net/JsonTypes/LocalServerInfo.cs b/Luski.net/JsonTypes/LocalServerInfo.cs index 4d65bb0..b124597 100644 --- a/Luski.net/JsonTypes/LocalServerInfo.cs +++ b/Luski.net/JsonTypes/LocalServerInfo.cs @@ -1,5 +1,6 @@ using System; using System.Text.Json.Serialization; +using Luski.Shared.PublicServers.V1.Enums; using Luski.Shared.PublicServers.V1.Shared; namespace Luski.net.JsonTypes; @@ -9,6 +10,15 @@ public class LocalServerInfo [JsonInclude] [JsonPropertyName("alternate_servers")] public ServerData[] AlternateServers { get; set; } = Array.Empty(); + [JsonInclude] + [JsonPropertyName("picture_type")] + public PictureType PictureType { get; set; } + [JsonInclude] + [JsonPropertyName("name")] + public string Name { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("description")] + public string Description { get; set; } = default!; } [JsonSerializable(typeof(LocalServerInfo))] @@ -16,7 +26,4 @@ public class LocalServerInfo GenerationMode = JsonSourceGenerationMode.Default, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, WriteIndented = false)] -internal partial class LocalServerInfoContext : JsonSerializerContext -{ - -} \ No newline at end of file +internal partial class LocalServerInfoContext : JsonSerializerContext; \ No newline at end of file diff --git a/Luski.net/Luski.net.csproj b/Luski.net/Luski.net.csproj index b4b67ea..7520fae 100755 --- a/Luski.net/Luski.net.csproj +++ b/Luski.net/Luski.net.csproj @@ -13,11 +13,11 @@ https://github.com/JacobTech-com/Luski.net True 1.0.0 - 2.0.0-alpha76 + 2.0.1-alpha15 - + diff --git a/Luski.net/PublicServer.Account.cs b/Luski.net/PublicServer.Account.cs index 6cbc47a..d1353de 100644 --- a/Luski.net/PublicServer.Account.cs +++ b/Luski.net/PublicServer.Account.cs @@ -48,7 +48,7 @@ public partial class PublicServer { EncryptionHandler.GenerateKeys(); } - while (!EncryptionHandler.Generated) { } + while (!EncryptionHandler.Generated) { Thread.Sleep(200); } Console.WriteLine("Encryption 2: " + DateTime.UtcNow.Subtract(dt).ToString("g")); List> FailedSystems = new(); login = true; diff --git a/Luski.net/PublicServer.Incoming.cs b/Luski.net/PublicServer.Incoming.cs index 3c01ab7..d2ba892 100644 --- a/Luski.net/PublicServer.Incoming.cs +++ b/Luski.net/PublicServer.Incoming.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.Json; +using System.Threading.Tasks; using JacobTechEncryption; using JacobTechEncryption.Enums; using Luski.net.Enums; @@ -8,7 +10,9 @@ using Luski.net.JsonTypes.BaseTypes; using Luski.net.JsonTypes.WSS; using Luski.net.Structures; using Luski.net.Structures.Public; +using Luski.Shared.PublicServers.V1.Enums; using Luski.Shared.PublicServers.V1.ServerToClient.HTTP; +using Luski.Shared.PublicServers.V1.Shared; using WebSocketSharp; using File = System.IO.File; using DataType = Luski.Shared.PublicServers.V1.Enums.DataType; @@ -35,12 +39,108 @@ public partial class PublicServer n.SessionToken); Token = n.Token; break; + case DataType.StatusUpdate: + StatusEvent se = JsonSerializer.Deserialize(data.Data!.ToString()!, StatusEventContext.Default.StatusEvent)!; + SocketUser u; + if (se.User == User.Id) u = User; + else + { + u = GetUser(se.User); + u.Status = se.After; + } + if (StatusUpdate is not null) + { + StatusUpdate.Invoke(se.Before, u); + } + break; + case DataType.Role: + RoleEvent re = JsonSerializer.Deserialize(data.Data!.ToString()!, RoleEventContext.Default.RoleEvent)!; + Role[] ra = roles.Where(s => s.ID == re.ID).ToArray(); + Role r; + bool @new = false; + if (ra.Length > 0) + { + r = ra[0]; + if (re.ServerPermissions is not null) r.ServerPermissions = re.ServerPermissions.Value; + if (re.Description is not null) r.Description = re.Description; + if (re.DisplayName is not null) r.DisplayName = re.DisplayName; + if (re.ColorType is not null) r.ColorType = re.ColorType.Value; + if (re.Color is not null) + { + if (r.ColorType == ColorType.Full) + { + Color nc = new(re.Color); + r.Colors = new []{nc}; + } + else + { + List cols = new(); + for (int i = 0; i < re.Color.Length - 7; i+=8) + { + cols.Add(new(re.Color[i..(i+8)])); + } + r.Colors = cols.ToArray(); + } + } + if (re.Index is not null) r.Index = re.Index.Value; + } + else + { + @new = true; + Task rr = GetRole(re.ID); + rr.Wait(); + r = rr.Result; + } + + if (RoleEvent is not null) _ = RoleEvent.Invoke(@new, r); + break; + case DataType.RoleMember: + RoleMemberEvent rme = JsonSerializer.Deserialize(data.Data!.ToString()!, RoleMemberEventContext.Default.RoleMemberEvent)!; + break; + case DataType.RoleDelete: + break; case DataType.MessageCreate: MessageSTC smsg = JsonSerializer.Deserialize(data.Data!.ToString()!, MessageSTCContext.Default.MessageSTC)!; List fl = new(); - foreach (var VARIABLE in smsg.Files) + List sf = new(); + foreach (ServerFileInfoSTC v in smsg.Files) { - fl.Add(VARIABLE.ID); + if (v.NameKey == 0) + { + if (string.IsNullOrEmpty(v.Name)) + { + v.Name = ""; + } + else v.Name = Encryption.Generic.Encoders[(int)v.NameEncoder] + .GetString(Convert.FromBase64String(v.Name)); + } + else + { + LocalKeyInfo key = EncryptionHandler.GetKey(v.NameKey); + switch (key.EncryptionType) + { + case EncryptionType.RSA: + v.Name = Encryption.RSA.Decrypt(Convert.FromBase64String(v.Name), key.Key, + v.NameEncoder); + break; + default: + v.Name = Encryption.Generic.Encoders[(int)v.NameEncoder] + .GetString(Convert.FromBase64String(v.Name)); + break; + } + } + fl.Add(v.ID); + sf.Add(new() + { + ID = v.ID, + Size = v.Size, + Name = v.Name, + Encoder = v.Encoder, + NameEncoder = v.NameEncoder, + Key = v.Key, + NameKey = v.NameKey, + Server = this + }); } if (smsg.EncryptionKey == 0) @@ -71,13 +171,15 @@ public partial class PublicServer { ID = smsg.ID, AuthorID = smsg.AuthorID, + TimeStamp = smsg.Timestamp, ChannelID = smsg.ChannelID, Context = smsg.Context, EncoderType = smsg.EncoderType, EncryptionKey = smsg.EncryptionKey, FileIDs = fl.ToArray(), Server = this, - IsProfile = smsg.IsProfile + ProfileID = smsg.ProfileID, + _Files = sf }; if (MessageReceived is not null) MessageReceived.Invoke(sm); break; diff --git a/Luski.net/PublicServer.cs b/Luski.net/PublicServer.cs index e2e6b7c..8da6be1 100644 --- a/Luski.net/PublicServer.cs +++ b/Luski.net/PublicServer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net.Http; using System.Text; @@ -18,7 +19,6 @@ using Luski.Shared.PublicServers.V1.Enums; using Luski.Shared.PublicServers.V1.ServerToClient.HTTP; using Luski.Shared.PublicServers.V1.Shared; using Role = Luski.net.Structures.Public.Role; -using SocketChannelProfile = Luski.net.Structures.Public.SocketChannelProfile; using SocketUser = Luski.net.Structures.Public.SocketUser; namespace Luski.net; @@ -26,6 +26,11 @@ namespace Luski.net; public partial class PublicServer : Server { public event Func? MessageReceived; + public event Func? StatusUpdate; + public event Func? RoleEvent; + public event Func? RoleDeleted; + public event Func? RoleMemberEvent; + public PictureType PictureType { get; private set; } public List chans { get; } = new(); public List cats { get; } = new(); public List roles { get; } = new(); @@ -37,7 +42,7 @@ public partial class PublicServer : Server base(Domain, API_Version, Secure) { } - internal static async Task GetServer(string Domain, string API_Version, bool Secure = true, bool GenerateEncryption = true, bool LogConsole = false) + internal static async Task GetServer(List Failed, string Domain, string API_Version, bool Secure = true, bool GenerateEncryption = true, bool LogConsole = false) { DateTime dt = DateTime.UtcNow; Console.WriteLine("Connecting to public server '{0}' using API {1}.", Domain, API_Version); @@ -62,8 +67,11 @@ public partial class PublicServer : Server } catch (Exception e) { - LocalServerInfo ServerListing = s.Storage.GetJson(StorageDirectory.ServerInfo, "Servers.json", true, + LocalServerInfo ServerListing = s.Storage.GetJson(StorageDirectory.ServerInfo, "server.json", true, LocalServerInfoContext.Default.LocalServerInfo); + s.Name = ServerListing.Name; + s.Description = ServerListing.Description; + s.PictureType = ServerListing.PictureType; if (ServerListing.AlternateServers.Length > 0) { Console.WriteLine("Failed to connect to public server '{0}' using API {1}. Attempting to connect to alternate servers.", Domain, API_Version); @@ -89,10 +97,23 @@ public partial class PublicServer : Server } } } - - if (si is null) throw; + + if (si is null) + { + Failed.Add(s); + throw; + } } + s.Storage.SetJson(StorageDirectory.ServerInfo, "server.json", new() + { + AlternateServers = Array.Empty(), + PictureType = si.PictureType, + Name = si.Name, + Description = si.Description + }, + LocalServerInfoContext.Default.LocalServerInfo); s.Name = si.Name; + s.PictureType = si.PictureType; s.Description = si.Description; s.wssurl = si.WSSv4Address; s.ServerType = ServerType.Public; @@ -159,6 +180,19 @@ public partial class PublicServer : Server Encryption.AES.Decrypt(Convert.FromBase64String(request.Name), nkey.Key)), _ => Encryption.Generic.Encoders[(short)request.TitleEncoderType].GetString(Convert.FromBase64String(request.Name)) }; + List cols = new(); + if (request.ColorType == ColorType.Full) + { + Color nc = new(request.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < request.Color.Length - 7; i+=8) + { + cols.Add(new(request.Color[i..(i+8)])); + } + } TCategory bob = new() { @@ -175,7 +209,8 @@ public partial class PublicServer : Server TitleEncoderType = request.TitleEncoderType, TitleEncryptionKey = request.TitleEncryptionKey, Server = this, - Color = new(request.Color) + ColorType = request.ColorType, + Colors = cols.ToArray() }; cats.Add(bob); return bob; @@ -196,15 +231,29 @@ public partial class PublicServer : Server if (r.Length > 0) return r[0]; RoleSTC s = await GetFromServer("SocketRole?id=" + id.ToString(), RoleSTCContext.Default.RoleSTC, CancellationToken.None); + List cols = new(); + if (s.ColorType == ColorType.Full) + { + Color nc = new(s.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < s.Color.Length - 7; i+=8) + { + cols.Add(new(s.Color[i..(i+8)])); + } + } + Role role = new() { Server = this, ID = s.ID, - Color = new(s.Color), + ColorType = s.ColorType, + Colors = cols.ToArray(), Description = s.Description, DisplayName = s.DisplayName, MembersListID = s.Members, - Name = s.Name, Index = s.Index, ServerPermissions = s.ServerPermissions }; @@ -212,39 +261,35 @@ public partial class PublicServer : Server return role; } - public async Task GetRoleOverride(long id) - { - RoleOverride[] r = roleso.Where(s => s.ID == id).ToArray(); - if (r.Length > 0) return r[0]; - UserRoleOverrideSTC s = await GetFromServer("SocketOverrides/RoleOverride/" + id.ToString(), UserRoleOverrideSTCContext.Default.UserRoleOverrideSTC, CancellationToken.None); - - RoleOverride role = new() - { - ID = s.Id, - BadPermissions = s.BadPermissions, - GoodPermissions = s.GoodPermissions, - ParentRoleID = s.RoleID, - Server = this - }; - roleso.Add(role); - return role; - } - public async Task GetRoles() { RolesSTC s = await GetFromServer("SocketRole/GetAll", RolesSTCContext.Default.RolesSTC, CancellationToken.None); roles.Clear(); foreach (var ServerRole in s.Roles) { + List cols = new(); + if (ServerRole.ColorType == ColorType.Full) + { + Color nc = new(ServerRole.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < ServerRole.Color.Length - 7; i+=8) + { + cols.Add(new(ServerRole.Color[i..(i+8)])); + } + } + roles.Add(new Role() { Server = this, ID = ServerRole.ID, - Color = new(ServerRole.Color), + ColorType = ServerRole.ColorType, + Colors = cols.ToArray(), Description = ServerRole.Description, DisplayName = ServerRole.DisplayName, MembersListID = ServerRole.Members, - Name = ServerRole.Name, Index = ServerRole.Index, ServerPermissions = ServerRole.ServerPermissions }); @@ -254,7 +299,47 @@ public partial class PublicServer : Server } public async Task SendMessage(TChannel channel, string msg, SocketMessage? ReplyTo = null, - SocketChannelProfile? FakeProfile = null) where TChannel : SocketChannel, new() + ServerProfile? FakeProfile = null, params string[] files) where TChannel : SocketChannel, new() + { + List lll = new(); + + foreach (var f in files) + { + lll.Add(await UploadFile(f)); + } + + return await SendMessage(channel, msg, ReplyTo, FakeProfile, lll.ToArray()); + } + + public async Task UploadFile(string File) + { + FileInfo FI = new FileInfo(File); + ServerFileInfoSTC res = await SendServer("SocketFile", File, ServerFileInfoSTCContext.Default.ServerFileInfoSTC, + CancellationToken.None, + new("name_encoder", "0"), + new("encoder", "0"), + new("name_encryption", "0"), + new("encryption", "0"), + new("name", Convert.ToBase64String(Encoding.UTF8.GetBytes(FI.Name)))); + if (res.ErrorMessage is not null || res.Error is not null) + { + Console.WriteLine("Error {0}: {1}", (res.Error is null ? "Unknown" : res.Error.Value), res.ErrorMessage); + } + return new SocketFile() + { + ID = res.ID, + Encoder = EncoderType.UTF8, + Key = 0, + Name = FI.Name, + NameEncoder = EncoderType.UTF8, + NameKey = 0, + Server = this, + Size = FI.Length + }; + } + + public async Task SendMessage(TChannel channel, string msg, SocketMessage? ReplyTo = null, + ServerProfile? FakeProfile = null, params SocketFile[] files) where TChannel : SocketChannel, new() { string bc = ""; if (channel.EncryptionKeys[0] == 0) @@ -271,17 +356,26 @@ public partial class PublicServer : Server _ => Encryption.AES.Encrypt(Encryption.Generic.Encoders[(int)channel.EncoderTypes[0]].GetBytes(msg), key.Key) }); } + + List lll = new(); + + foreach (var f in files) + { + lll.Add(f.ID); + } + + MessageCTS pcsm = new() { - Files = Array.Empty(), + Files = lll.ToArray(), ChannelID = channel.ID, EncryptionKey = channel.EncryptionKeys[0], Encoding = channel.EncoderTypes[0], - Base64Context = bc + Base64Context = bc, }; if (FakeProfile is not null) { - pcsm.Profile = FakeProfile.Id; + pcsm.Profile = FakeProfile.ID; } @@ -298,16 +392,85 @@ public partial class PublicServer : Server { ID = smsg.ID, AuthorID = smsg.AuthorID, + ProfileID = smsg.ProfileID, ChannelID = channel.ID, + TimeStamp = smsg.Timestamp, Context = msg, EncoderType = smsg.EncoderType, EncryptionKey = smsg.EncryptionKey, FileIDs = fl.ToArray(), Server = channel.Server, - IsProfile = smsg.IsProfile + _Files = files.ToList() }; return sm; } + + public async Task CreateRole(RolePostCTS Req) + { + RoleSTC res = await SendServer("SocketRole", + Req, + RolePostCTSContext.Default.RolePostCTS, + RoleSTCContext.Default.RoleSTC, + CancellationToken.None); + List cols = new(); + if (res.ColorType == ColorType.Full) + { + Color nc = new(res.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < res.Color.Length - 7; i+=8) + { + cols.Add(new(res.Color[i..(i+8)])); + } + } + + Role role = new Role() + { + DisplayName = res.DisplayName, + ServerPermissions = res.ServerPermissions, + Description = res.Description, + Index = res.Index, + MembersListID = res.Members, + ColorType = res.ColorType, + Colors = cols.ToArray(), + Server = this, + ID = res.ID + }; + roles.Add(role); + return role; + } + + public async Task EditRole(Role role, string? Name = null, string? Description = null, int? Index = null, ServerPermission? Permissions = null, string? Color = null, ColorType? colorType = null) + { + RoleSTC res = await SendServerPatch("SocketRole", + new() + { + ID = role.ID, + Description = Description, + DisplayName = Name, + Index = Index, + ColorType = colorType, + Color = Color, + ServerPermissions = Permissions + }, + RolePatchCTSContext.Default.RolePatchCTS, + RoleSTCContext.Default.RoleSTC, + CancellationToken.None); + if (Permissions is not null) role.ServerPermissions = res.ServerPermissions; + if (Description is not null) role.Description = res.Description; + if (Index is not null) role.Index = res.Index; + if (Name is not null) role.DisplayName = res.DisplayName; + if (Color is not null) role.Colors = new []{new Color(res.Color)}; + if (colorType is not null) role.ColorType = res.ColorType; + return role; + } + + public async Task EditRoleMembers(Role r) + { + return r; + } public async Task GetChannel(long id, CancellationToken CancellationToken) where TChannel : SocketChannel, new() { @@ -365,6 +528,19 @@ public partial class PublicServer : Server Encryption.AES.Decrypt(Convert.FromBase64String(request.Name), nkey.Key)), _ => Encryption.Generic.Encoders[(short)request.TitleEncoderType].GetString(Convert.FromBase64String(request.Name)) }; + List cols = new(); + if (request.ColorType == ColorType.Full) + { + Color nc = new(request.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < request.Color.Length - 7; i+=8) + { + cols.Add(new(request.Color[i..(i+8)])); + } + } TChannel bob = new() { @@ -384,7 +560,8 @@ public partial class PublicServer : Server TitleEncryptionKey = request.TitleEncryptionKey, PictureType = request.PictureType, Server = this, - Color = new(request.Color) + ColorType = request.ColorType, + Colors = cols.ToArray() }; chans.Add(bob); @@ -415,7 +592,7 @@ public partial class PublicServer : Server Parent = parent.ID, DescriptionEncryptionKey = 0, TitleEncryptionKey = 0, - RoleOverrides = Array.Empty(), + RoleOverrides = Array.Empty(), UserOverrides = Array.Empty(), Type = ChannelType.TextAndVoice, Color = "FFFFFFFF", @@ -424,6 +601,20 @@ public partial class PublicServer : Server ChannelPostCTSContext.Default.ChannelPostCTS, ChannelSTCContext.Default.ChannelSTC, CancellationToken.None); + List cols = new(); + if (res.ColorType == ColorType.Full) + { + Color nc = new(res.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < res.Color.Length - 7; i+=8) + { + cols.Add(new(res.Color[i..(i+8)])); + } + } + return new SocketChannel() { ID = res.ID, @@ -442,7 +633,8 @@ public partial class PublicServer : Server TitleEncryptionKey = res.TitleEncryptionKey, PictureType = res.PictureType, Server = this, - Color = new(res.Color) + ColorType = res.ColorType, + Colors = cols.ToArray() }; } @@ -488,8 +680,7 @@ public partial class PublicServer : Server { Server = this, Id = user.ID, - DisplayName = user.DisplayName, - PictureType = user.PictureType, + ServerProfile = user.ServerProfile, RoleIds = user.RoleIds, Status = user.Status }; @@ -500,9 +691,8 @@ public partial class PublicServer : Server { Server = this, Id = user.ID, - DisplayName = user.DisplayName, + ServerProfile = user.ServerProfile, SelectedChannel = user.SelectedChannel, - PictureType = user.PictureType, RoleIds = user.RoleIds, Status = user.Status, } as Tuser)!; @@ -511,32 +701,31 @@ public partial class PublicServer : Server return u; } - public async Task GetChannelProfile(long ProfileId, CancellationToken CancellationToken) + public Tuser GetUser(long UserId) where Tuser : SocketUser, new() { - ChannelProfileSTC user; - if (profiles.Count > 0 && profiles.Any(s => s.Id == ProfileId)) + SocketUserSTC user; + if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId)) { - SocketChannelProfile temp = profiles.Where(s => s.Id == ProfileId).FirstOrDefault()!; + Tuser temp = poeople.Where(s => s is Tuser && s.Id == UserId).Cast().FirstOrDefault()!; return temp; } while (true) { if (CanRequest) { - user = await GetFromServer("socketchannelprofile", - ChannelProfileSTCContext.Default.ChannelProfileSTC, - CancellationToken, - new KeyValuePair("id", ProfileId.ToString())); + user = GetFromServerRaw("socketuser", + SocketUserSTCContext.Default.SocketUserSTC, + new KeyValuePair("id", UserId.ToString())); break; } } if (user is null) throw new Exception("Server did not return a user"); - if (profiles.Count > 0 && profiles.Any(s => s.Id == ProfileId)) + if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId)) { - foreach (SocketChannelProfile? p in profiles.Where(s => s.Id == ProfileId)) + foreach (IUser? p in poeople.Where(s => s.Id == UserId)) { - profiles.Remove(p); + poeople.Remove(p); } } if (user is null || user.Error is not null) @@ -546,19 +735,167 @@ public partial class PublicServer : Server throw new Exception($"Something went wrong getting your user information\n{error}"); } - SocketChannelProfile u = new() + Tuser u = new(); + if (typeof(Tuser).FullName == typeof(SocketUser).FullName) + { + u = new() + { + Server = this, + Id = user.ID, + ServerProfile = user.ServerProfile, + RoleIds = user.RoleIds, + Status = user.Status + }; + } + else + { + u = (new SocketAppUser() + { + Server = this, + Id = user.ID, + ServerProfile = user.ServerProfile, + SelectedChannel = user.SelectedChannel, + RoleIds = user.RoleIds, + Status = user.Status, + } as Tuser)!; + } + poeople.Add(u); + return u; + } + + public async Task GetProfile(long ProfileId, CancellationToken CancellationToken) + { + ProfileSTC user; + if (profiles.Count > 0 && profiles.Any(s => s.ID == ProfileId)) + { + ServerProfile temp = profiles.Where(s => s.ID == ProfileId).FirstOrDefault()!; + return temp; + } + while (true) + { + if (CanRequest) + { + user = await GetFromServer("socketprofile", + ChannelProfileSTCContext.Default.ProfileSTC, + CancellationToken, + new KeyValuePair("id", ProfileId.ToString())); + break; + } + } + + if (user is null) throw new Exception("Server did not return a user"); + if (profiles.Count > 0 && profiles.Any(s => s.ID == ProfileId)) + { + _ = profiles.RemoveAll(s => s.ID == ProfileId); + } + if (user is null || user.Error is not null) + { + string error = "User was null"; + if (user is not null && user.Error is not null) error = $"{user.Error}: {user.ErrorMessage}"; + throw new Exception($"Something went wrong getting your user information\n{error}"); + } + + Color[]? colss = null; + if (user.Color is not null) + { + List cols = new(); + if (user.ColorType == ColorType.Full) + { + Color nc = new(user.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < user.Color.Length - 7; i+=8) + { + cols.Add(new(user.Color[i..(i+8)])); + } + } + colss = cols.ToArray(); + } + + + ServerProfile u = new() { Server = this, - Id = user.ID, + ID = user.ID, DisplayName = user.DisplayName, PictureType = user.PictureType, Controllers = user.Controllers, - Color = new(user.Color) + RoleControllers = user.RoleControllers, + ColorType = user.ColorType, + Color = colss }; - poeople.Add(u); + profiles.Add(u); return u; } + public async Task GetMyProfiles(CancellationToken CancellationToken) + { + ProfileListSTC Prof; + while (true) + { + if (CanRequest) + { + Prof = await GetFromServer("socketprofile/myprofiles", + ProfileListSTCContext.Default.ProfileListSTC, + CancellationToken); + break; + } + } + + if (Prof is null) throw new Exception("Server did not return a Profile List"); + List profiles_ = new(); + foreach (ProfileSTC user in Prof.Profiles) + { + if (profiles.Count > 0 && profiles.Any(s => s.ID == user.ID)) + { + _ = profiles.RemoveAll(s => s.ID == user.ID); + } + if (user is null || user.Error is not null) + { + string error = "Profile was null"; + if (user is not null && user.Error is not null) error = $"{user.Error}: {user.ErrorMessage}"; + throw new Exception($"Something went wrong getting your profile information\n{error}"); + } + + Color[]? colss = null; + if (user.Color is not null) + { + List cols = new(); + if (user.ColorType == ColorType.Full) + { + Color nc = new(user.Color); + cols.Add(nc); + } + else + { + for (int i = 0; i < user.Color.Length - 7; i+=8) + { + cols.Add(new(user.Color[i..(i+8)])); + } + } + colss = cols.ToArray(); + } + + ServerProfile u = new() + { + Server = this, + ID = user.ID, + DisplayName = user.DisplayName, + PictureType = user.PictureType, + Controllers = user.Controllers, + RoleControllers = user.RoleControllers, + ColorType = user.ColorType, + Color = colss + }; + profiles_.Add(u); + profiles.Add(u); + } + + return profiles_.ToArray(); + } + /// /// Sends the server a request to update the of you account /// diff --git a/Luski.net/Server.Globals.cs b/Luski.net/Server.Globals.cs index ef7ddbb..a3f4e04 100644 --- a/Luski.net/Server.Globals.cs +++ b/Luski.net/Server.Globals.cs @@ -23,5 +23,5 @@ public partial class Server public bool IsLogedIn => Token is not null; internal bool CanRequest = false, login = false; internal List poeople = new(); - internal List profiles = new(); + internal List profiles = new(); } \ No newline at end of file diff --git a/Luski.net/Server.Storage.cs b/Luski.net/Server.Storage.cs index 4804315..eba88b6 100644 --- a/Luski.net/Server.Storage.cs +++ b/Luski.net/Server.Storage.cs @@ -32,6 +32,7 @@ public class ServerStorage private static readonly int[] CantDelete = new[] { + (int)StorageDirectory.ServerInfo, (int)StorageDirectory.ChannelKeys, (int)StorageDirectory.ServerKeys, (int)StorageDirectory.StorageInfo @@ -88,6 +89,12 @@ public class ServerStorage return JsonSerializer.Deserialize(s, JsonInfo)!; } + public void SetJson(StorageDirectory Directory, string Resource, TResult obj, JsonTypeInfo JsonInfo) where TResult : new() + { + string FilePath = GetResourceDirectory(Directory, Resource); + File.WriteAllText(FilePath, JsonSerializer.Serialize(obj, JsonInfo)); + } + public byte[] UpdateStorage(byte[] OldPassword) { diff --git a/Luski.net/Server.cs b/Luski.net/Server.cs index 441aa11..c67ce58 100644 --- a/Luski.net/Server.cs +++ b/Luski.net/Server.cs @@ -101,6 +101,23 @@ public partial class Server if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" }; return temp; } + + public Tresult GetFromServerRaw(string Path, JsonTypeInfo Type, params KeyValuePair[] Headers) where Tresult : STC, new() + { + HttpResponseMessage ServerResponce = GetFromServer(Path, CancellationToken.None, Headers); + Tresult temp = new(); + string raw =""; + try + { + temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStream(), Type)!; + } + catch (Exception e) + { + Console.WriteLine("JSON parse failed for the following data as type {0}\n{1}", temp.GetType(), raw); + } + if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" }; + return temp; + } public async Task SendServer(string Path, Tvalue Payload, JsonTypeInfo jsonTypeInfo, JsonTypeInfo ReturnjsonTypeInfo, CancellationToken CancellationToken, params KeyValuePair[] Headers) where Tvalue : CTS where Tresult : STC, new() { diff --git a/Luski.net/Structures/Main/MainSocketTextChannel.cs b/Luski.net/Structures/Main/MainSocketTextChannel.cs index 4674af9..6a2a64b 100755 --- a/Luski.net/Structures/Main/MainSocketTextChannel.cs +++ b/Luski.net/Structures/Main/MainSocketTextChannel.cs @@ -27,8 +27,9 @@ public class MainSocketTextChannel : MainSocketChannel public async Task GetPicture(CancellationToken CancellationToken) { - if (Type == ChannelType.DM) return Members.First().GetAvatar(CancellationToken).Result; - else + throw new NotImplementedException(); + //if (Type == ChannelType.DM) return Members.First().GetAvatar(CancellationToken).Result; + // else { bool isc = System.IO.File.Exists(Server.Storage.GetStorageDirectory(StorageDirectory.ChannelIcons) + Id.ToString()); if (!isc) await Server.GetFromServer($"SocketChannel/GetPicture/{Id}", Server.Storage.GetStorageDirectory(StorageDirectory.ChannelIcons) + Id.ToString(), CancellationToken); diff --git a/Luski.net/Structures/Public/Color.cs b/Luski.net/Structures/Public/Color.cs index 02156c6..1d01bd9 100644 --- a/Luski.net/Structures/Public/Color.cs +++ b/Luski.net/Structures/Public/Color.cs @@ -2,39 +2,59 @@ using System; namespace Luski.net.Structures.Public; -public class Color +public struct Color { public Color(string servercol) { - Bytes = Convert.FromHexString(servercol); + byte[] t = Convert.FromHexString(servercol); + r = t[0]; + g = t[1]; + b = t[2]; + a = t[3]; + } + + public static bool operator ==(Color a, Color b) + { + return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; + } + + public static bool operator !=(Color a, Color b) + { + return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a; } public Color(byte R, byte G, byte B, byte A) { - Bytes = new byte[] {R, G, B, A}; + r = R; + g = G; + b = B; + a = A; } public string ToDatabaseStr() { - return Convert.ToHexString(Bytes); + return Convert.ToHexString(new []{r,g,b,a}); } - private byte[] Bytes; + private byte r; + private byte g; + private byte b; + private byte a; public byte A { - get => Bytes[3]; + get => a; } public byte R { - get => Bytes[0]; + get => r; } public byte G { - get => Bytes[1]; + get => g; } public byte B { - get => Bytes[2]; + get => b; } } \ No newline at end of file diff --git a/Luski.net/Structures/Public/Role.cs b/Luski.net/Structures/Public/Role.cs index 9a8e332..b201e89 100644 --- a/Luski.net/Structures/Public/Role.cs +++ b/Luski.net/Structures/Public/Role.cs @@ -9,18 +9,28 @@ public class Role { public required PublicServer Server { get; init; } = default!; public required long ID { get; init; } = default!; - public required string Name { get; init; } = default!; - public required int Index { get; init; } = default!; - public required Color Color { get; init; } = default!; - public required string Description { get; init; } = default!; - public required string DisplayName { get; init; } = default!; - public required ServerPermission ServerPermissions { get; init; } = default!; - public required long[] MembersListID { get; init; } = default!; + public int Index { get; internal set; } = default!; + public ColorType ColorType { get; internal set; } = ColorType.Full; + public Color[] Colors { get; internal set; } = default!; + public string Description { get; internal set; } = default!; + public string DisplayName { get; internal set; } = default!; + public ServerPermission ServerPermissions { get; internal set; } = default!; + public long[] MLID = default!; + + public long[] MembersListID + { + get => MLID; + internal set + { + MLID = value; + RawUsers = null; + } + } private List? RawUsers = null; public async Task GetMembers() { - if (RawUsers is null) + if (RawUsers is null || RawUsers.Count != MembersListID.Length) { RawUsers = new(); foreach (long m in MembersListID) diff --git a/Luski.net/Structures/Public/RoleOverride.cs b/Luski.net/Structures/Public/RoleOverride.cs index a83cd7a..17f52a3 100644 --- a/Luski.net/Structures/Public/RoleOverride.cs +++ b/Luski.net/Structures/Public/RoleOverride.cs @@ -6,7 +6,6 @@ namespace Luski.net.Structures.Public; public class RoleOverride { - public long ID { get; init; } public long ParentRoleID { get; init; } public ServerPermission GoodPermissions { get; set; } diff --git a/Luski.net/Structures/Public/SocketChannelProfile.cs b/Luski.net/Structures/Public/ServerProfile.cs similarity index 52% rename from Luski.net/Structures/Public/SocketChannelProfile.cs rename to Luski.net/Structures/Public/ServerProfile.cs index 4a32322..2ac1694 100644 --- a/Luski.net/Structures/Public/SocketChannelProfile.cs +++ b/Luski.net/Structures/Public/ServerProfile.cs @@ -3,32 +3,36 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Luski.net.Enums; -using Luski.net.Interfaces; using Luski.Shared.PublicServers.V1.Enums; namespace Luski.net.Structures.Public; -public class SocketChannelProfile : IUser +public class ServerProfile { public PublicServer Server { get; init; } = default!; - public long Id { get; init; } = default!; + public long ID { get; init; } = default!; public string DisplayName { get; init; } = default!; - public virtual UserStatus Status { get; init; } = UserStatus.Online; - public PictureType PictureType { get; init; } = default!; + public PictureType? PictureType { get; init; } = default!; public long[] Controllers { get; internal set; } = default!; + public long[] RoleControllers { get; internal set; } = default!; + internal ColorType? ColorType { get; set; } = default!; + internal Color[]? Color { get; set; } = default!; - internal Color Color { get; set; } = default!; - - public Task GetColor() + public Task GetColors() { return Task.FromResult(Color); } + public Task GetColorType() + { + return Task.FromResult(ColorType); + } + public async Task GetAvatar(CancellationToken CancellationToken) { - bool isc = System.IO.File.Exists(Server.Storage.GetStorageDirectory(StorageDirectory.ProfileAvatars) + Id.ToString()); - if (!isc) await Server.GetFromServer($"socketchannelprofile/Avatar/{Id}", Server.Storage.GetStorageDirectory(StorageDirectory.ProfileAvatars) + Id.ToString(), CancellationToken); - return Server.Storage.GetResourceStream(StorageDirectory.ProfileAvatars, Id.ToString()); + bool isc = System.IO.File.Exists(Server.Storage.GetStorageDirectory(StorageDirectory.ProfileAvatars) + ID.ToString()); + if (!isc) await Server.GetFromServer($"socketprofile/Avatar/{ID}", Server.Storage.GetStorageDirectory(StorageDirectory.ProfileAvatars) + ID.ToString(), CancellationToken); + return Server.Storage.GetResourceStream(StorageDirectory.ProfileAvatars, ID.ToString()); } public Task GetUserKeys(CancellationToken CancellationToken) diff --git a/Luski.net/Structures/Public/SocketAppUser.cs b/Luski.net/Structures/Public/SocketAppUser.cs index 9300ac6..68cd69c 100755 --- a/Luski.net/Structures/Public/SocketAppUser.cs +++ b/Luski.net/Structures/Public/SocketAppUser.cs @@ -10,12 +10,23 @@ namespace Luski.net.Structures.Public; public class SocketAppUser : SocketUser { public long SelectedChannel { get; init; } = default!; + + private List? _serverProfiles; public async Task GetSelectedChannel(CancellationToken Token) { return await Server.GetChannel(SelectedChannel, Token); } + public async Task GetProfiles(CancellationToken Token) + { + if (_serverProfiles is null) + { + _serverProfiles = (await Server.GetMyProfiles(Token)).ToList(); + } + return _serverProfiles.ToArray(); + } + public async Task HasAccessToCategory(SocketCategory Category, ServerPermission RequiredPerms = ServerPermission.ViewThis) { if (Category.Server != Server) return false; @@ -30,8 +41,10 @@ public class SocketAppUser : SocketUser { if (CatUserOveride.UserID != Id) continue; if ((CatUserOveride.BadPermissions & RequiredPerms) > ServerPermission.None) return false; + if ((CatUserOveride.GoodPermissions & RequiredPerms) == RequiredPerms) return true; GoodPerms |= CatUserOveride.GoodPermissions; + break; } RoleOverride[] CatRoleOverides = await Category.GetRoleOverrides(); diff --git a/Luski.net/Structures/Public/SocketCategory.cs b/Luski.net/Structures/Public/SocketCategory.cs index 630ba13..fd8aef7 100644 --- a/Luski.net/Structures/Public/SocketCategory.cs +++ b/Luski.net/Structures/Public/SocketCategory.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using JacobTechEncryption.Enums; +using Luski.Shared.PublicServers.V1.Enums; +using Luski.Shared.PublicServers.V1.ServerToClient.HTTP; namespace Luski.net.Structures.Public; @@ -10,10 +12,11 @@ public class SocketCategory { public PublicServer Server { get; init; } = default!; public long ID { get; init; } - public Color Color { get; init; } + public ColorType ColorType { get; init; } = ColorType.Full; + public Color[] Colors { get; init; } internal long ParentID { get; set; } - internal long[] RoleOverides { get; set; } - internal long[] UserOverides { get; set; } + internal RoleOverrideSTC[] RoleOverides { get; set; } + internal UserOverrideSTC[] UserOverides { get; set; } internal long[] Channels { get; set; } internal long[] Categories { get; set; } SocketCategory? RawParent = null; diff --git a/Luski.net/Structures/Public/SocketChannel.cs b/Luski.net/Structures/Public/SocketChannel.cs index ad4b9fc..328f757 100644 --- a/Luski.net/Structures/Public/SocketChannel.cs +++ b/Luski.net/Structures/Public/SocketChannel.cs @@ -15,11 +15,12 @@ namespace Luski.net.Structures.Public; public class SocketChannel { public PublicServer Server { get; init; } = default!; - public Color Color { get; init; } + public ColorType ColorType { get; init; } = ColorType.Full; + public Color[] Colors { get; init; } public long ID { get; internal set; } internal long CategoryID { get; set; } - internal long[] RoleOverrides { get; set; } - internal long[] UserOverrides { get; set; } + internal RoleOverrideSTC[] RoleOverrides { get; set; } + internal UserOverrideSTC[] UserOverrides { get; set; } SocketCategory? RawParent = null; List? RawRoleOverides = null; List? RawUserOverides = null; @@ -136,6 +137,7 @@ public class SocketChannel { Server = Server, ID = i.ID, + TimeStamp = i.Timestamp, ChannelID = ID, AuthorID = i.AuthorID, Context = i.Context, @@ -143,7 +145,7 @@ public class SocketChannel EncoderType = i.EncoderType, FileIDs = ff.ToArray(), _Files = sf, - IsProfile = i.IsProfile + ProfileID = i.ProfileID }); } return await Task.FromResult(mmmm.AsReadOnly()); @@ -281,11 +283,12 @@ public class SocketChannel ChannelID = ID, AuthorID = i.AuthorID, Context = i.Context, + TimeStamp = i.Timestamp, EncryptionKey = i.EncryptionKey, EncoderType = i.EncoderType, FileIDs = ff.ToArray(), _Files = sf, - IsProfile = i.IsProfile + ProfileID = i.ProfileID }); } return await Task.FromResult(mmmm.AsReadOnly()); @@ -311,11 +314,19 @@ public class SocketChannel } public async Task SendMessage(string msg, SocketMessage? ReplyTo = null, - SocketChannelProfile? FakeProfile = null) + ServerProfile? Profile = null, params string[] files) { - return await Server.SendMessage(this, msg, ReplyTo, FakeProfile); + return await Server.SendMessage(this, msg, ReplyTo, Profile, files); } + public async Task SendMessage(string msg, SocketMessage? ReplyTo = null, + ServerProfile? Profile = null, params SocketFile[] files) + { + return await Server.SendMessage(this, msg, ReplyTo, Profile, files); + } + + + public async Task GetPicture(CancellationToken CancellationToken) { bool isc = System.IO.File.Exists(Server.Storage.GetStorageDirectory(StorageDirectory.ChannelIcons) + ID.ToString()); @@ -337,18 +348,24 @@ public class SocketChannel public DateTime Epoch { get; internal set; } public string Name { get; internal set; } public string Description { get; internal set; } - public async Task GetRoleOverrides() + public Task GetRoleOverrides() { if (RawRoleOverides is null) { RawRoleOverides = new(); - foreach (long ro in RoleOverrides) + foreach (var ro in RoleOverrides) { - RawRoleOverides.Add(await Server.GetRoleOverride(ro)); + RawRoleOverides.Add(new() + { + Server = this.Server, + ParentRoleID = ro.RoleID, + GoodPermissions = ro.GoodPermissions, + BadPermissions = ro.BadPermissions + }); } } - return RawRoleOverides!.ToArray(); + return Task.FromResult(RawRoleOverides!.ToArray()); } public Task GetUserOverride() { diff --git a/Luski.net/Structures/Public/SocketFile.cs b/Luski.net/Structures/Public/SocketFile.cs index db14fdc..8651e77 100644 --- a/Luski.net/Structures/Public/SocketFile.cs +++ b/Luski.net/Structures/Public/SocketFile.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using JacobTechEncryption.Enums; using Luski.net.Enums; +using Luski.Shared.PublicServers.V1.Enums; namespace Luski.net.Structures.Public; diff --git a/Luski.net/Structures/Public/SocketMessage.cs b/Luski.net/Structures/Public/SocketMessage.cs index fec334c..ac10319 100644 --- a/Luski.net/Structures/Public/SocketMessage.cs +++ b/Luski.net/Structures/Public/SocketMessage.cs @@ -10,17 +10,19 @@ public class SocketMessage { public required PublicServer Server { get; init; } = default!; public required long ID { get; init; } + public required long TimeStamp { get; init; } public required long ChannelID { get; init; } public required long AuthorID { get; init; } + public required long ProfileID { get; init; } public string Context { get; internal set; } public required long EncryptionKey { get; init; } public long[] FileIDs { get; internal set; } - public required bool IsProfile { get; init; } public EncoderType EncoderType { get; internal set; } private SocketChannel? RawParent; private IUser? au; - internal List _Files = new(); - + private ServerProfile? ap; + internal List _Files { get; set; } = new(); + public IReadOnlyList Files { get => _Files.AsReadOnly(); @@ -40,18 +42,21 @@ public class SocketMessage { if (au is null) { - if (IsProfile) - { - au = await Server.GetChannelProfile(AuthorID, token); - } - else - { - if (AuthorID == Server.User.Id) au = Server.User; - else au = await Server.GetUser(AuthorID, token); - } - + if (AuthorID == Server.User.Id) au = Server.User; + else au = await Server.GetUser(AuthorID, token); } return au; } + + public async Task GetProfile(CancellationToken token) + { + if (ap is null) + { + ap = await Server.GetProfile(ProfileID, token); + + } + + return ap; + } } \ No newline at end of file diff --git a/Luski.net/Structures/Public/SocketUser.cs b/Luski.net/Structures/Public/SocketUser.cs index cdee224..1d6d889 100644 --- a/Luski.net/Structures/Public/SocketUser.cs +++ b/Luski.net/Structures/Public/SocketUser.cs @@ -9,6 +9,7 @@ using Luski.net.Interfaces; using Luski.net.JsonTypes; using Luski.Shared.PublicServers.V1.Enums; using Luski.Shared.PublicServers.V1.ServerToClient.HTTP; +using Luski.Shared.PublicServers.V1.Shared; namespace Luski.net.Structures.Public; @@ -16,15 +17,19 @@ public class SocketUser : IUser { public PublicServer Server { get; init; } = default!; public long Id { get; init; } = default!; - public string DisplayName { get; init; } = default!; public virtual UserStatus Status { get; internal set; } = default!; - public PictureType PictureType { get; init; } = default!; + public long ServerProfile { get; init; } public long[] RoleIds { get; init; } = default!; private List? RawRoles = null; - public async Task GetColor() + public async Task GetColorType() { - return (await GetRoles())[0].Color; + return (await GetRoles())[0].ColorType; + } + + public async Task GetColors() + { + return (await GetRoles())[0].Colors; } public async Task GetRoles() @@ -49,6 +54,19 @@ public class SocketUser : IUser if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", Server.Storage.GetStorageDirectory(StorageDirectory.Avatars) + Id.ToString(), CancellationToken); return Server.Storage.GetResourceStream(StorageDirectory.Avatars, Id.ToString()); } + + public async Task HasPermissions(ServerPermission RequiredPerms) + { + if (Server.OwnerID == Id) return true; + Role[] UserRoleIDList = await GetRoles(); + ServerPermission op = ServerPermission.None; + foreach (Role RoleID in UserRoleIDList) + { + op |= RoleID.ServerPermissions; + } + + return op.HasPermission(RequiredPerms); + } public Task GetUserKeys(CancellationToken CancellationToken) {