Better Storage.

The example library now has better storage for local information and cache.
This commit is contained in:
JacobTech 2023-07-10 07:35:05 -04:00
parent d8fbf281d0
commit c3bb39b21b
19 changed files with 353 additions and 199 deletions

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Luski.net.Enums;
using Luski.net.Structures.Main; using Luski.net.Structures.Main;
using Luski.net.Structures.Public; using Luski.net.Structures.Public;
@ -19,6 +20,9 @@ public class API
{ {
Domain = Domain, Domain = Domain,
ApiVersion = Version, ApiVersion = Version,
Storage = new(Domain),
EncryptionHandler = new(Domain),
ServerType = ServerType.Public
}; };
InternalServers.Add(s); InternalServers.Add(s);
return s; return s;
@ -30,6 +34,9 @@ public class API
{ {
Domain = Domain, Domain = Domain,
ApiVersion = Version, ApiVersion = Version,
Storage = new(Domain),
EncryptionHandler = new(Domain),
ServerType = ServerType.Main
}; };
return MainServer; return MainServer;
} }

View File

@ -1,51 +1,19 @@
using Luski.net.Enums; /*using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using JacobTechEncryption;
namespace Luski.net namespace Luski.net
{ {
public static class ClientEncryption public static class ClientEncryption
{ {
internal static string? MyPublicKey;
internal static readonly UnicodeEncoding Encoder = new();
private static string? myPrivateKey;
internal static bool Generating = false;
internal static bool Generated = false;
private static string? _serverpublickey = null;
internal static string? ofkey = null;
internal static string? outofkey = null;
internal static string pw = ""; internal static string pw = "";
public static int NewKeySize = 4096;
public static void GenerateKeys()
{
if (!Generating)
{
Generating = true;
GenerateNewKeys(out MyPublicKey, out myPrivateKey);
GenerateNewKeys(out outofkey, out ofkey);
Generated = true;
}
}
public static void GenerateNewKeys(out string Public, out string Private)
{
using RSACryptoServiceProvider r = new(NewKeySize);
Private = r.ToXmlString(true);
Public = r.ToXmlString(false);
return;
}
public static class File public static class File
{ {/*
internal static void SetOfflineKey(string key) internal static void SetOfflineKey(string key)
{ {
MakeFile("Server.GetKeyFilePath", pw); MakeFile("Server.GetKeyFilePath", pw);
@ -54,11 +22,7 @@ namespace Luski.net
fileLayout.Save("Server.GetKeyFilePath", pw); fileLayout.Save("Server.GetKeyFilePath", pw);
} }
public static LuskiDataFile GetFile()
{
MakeFile("Server.GetKeyFilePath", pw);
return JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw))!;
}
internal static string? GetOfflineKey() internal static string? GetOfflineKey()
{ {
@ -67,6 +31,12 @@ namespace Luski.net
return fileLayout?.OfflineKey; return fileLayout?.OfflineKey;
} }
public static LuskiDataFile GetFile()
{
MakeFile("Server.GetKeyFilePath", pw);
return JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw))!;
}
private static string FileString(string path, string password) private static string FileString(string path, string password)
{ {
byte[] passwordBytes = Encoding.UTF8.GetBytes(password); byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
@ -112,14 +82,14 @@ namespace Luski.net
public static class Channels public static class Channels
{ {
public static string GetKey(long channel) private static string GetKey(long channel)
{ {
LuskiDataFile? fileLayout; LuskiDataFile? fileLayout;
IEnumerable<ChannelLayout>? lis; IEnumerable<ChannelLayout>? lis;
try try
{ {
#pragma warning disable CS8603 // Possible null reference return. #pragma warning disable CS8603 // Possible null reference return.
if (channel == 0) return myPrivateKey; // if (channel == 0) return myPrivateKey;
#pragma warning restore CS8603 // Possible null reference return. #pragma warning restore CS8603 // Possible null reference return.
MakeFile("Server.GetKeyFilePath", pw); MakeFile("Server.GetKeyFilePath", pw);
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw)); fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw));
@ -144,7 +114,7 @@ namespace Luski.net
try try
{ {
#pragma warning disable CS8603 // Possible null reference return. #pragma warning disable CS8603 // Possible null reference return.
if (channel == 0) return myPrivateKey; // if (channel == 0) return myPrivateKey;
#pragma warning restore CS8603 // Possible null reference return. #pragma warning restore CS8603 // Possible null reference return.
MakeFile("Server.GetKeyFilePathBr(branch.ToString())", pw); MakeFile("Server.GetKeyFilePathBr(branch.ToString())", pw);
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("", pw)); fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("", pw));
@ -273,8 +243,7 @@ namespace Luski.net
public string key { get; set; } = default!; public string key { get; set; } = default!;
} }
} }
/* public class AES
public class AES
{ {
public static string Encrypt(string path, string Password) public static string Encrypt(string path, string Password)
{ {
@ -301,12 +270,10 @@ namespace Luski.net
msEncrypt.Dispose(); msEncrypt.Dispose();
return p; return p;
/*
string p = Path.GetTempFileName();
string p = Path.GetTempFileName();
byte[] salt = new byte[100]; byte[] salt = new byte[100];
RNGCryptoServiceProvider provider = new(); RNGCryptoServiceProvider provider = new();
provider.GetBytes(salt); provider.GetBytes(salt);
@ -378,27 +345,7 @@ namespace Luski.net
fsOut.Dispose(); fsOut.Dispose();
} }
} }
*/
internal const int PasswordVersion = 0;
internal static byte[] LocalPasswordEncrypt(byte[] Password, int PasswordVersion = PasswordVersion)
{
return PasswordVersion switch
{
0 => SHA256.Create().ComputeHash(Password),
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
};
}
internal static string RemotePasswordEncrypt(byte[] Password, int PasswordVersion = PasswordVersion)
{
return PasswordVersion switch
{
0 => Convert.ToBase64String(Encryption.RSA.Encrypt(LocalPasswordEncrypt(Password, PasswordVersion), MyPublicKey)),
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
};
}
/*
public static byte[] Hash(byte[] data) public static byte[] Hash(byte[] data)
{ {
return SHA256.Create().ComputeHash(data); return SHA256.Create().ComputeHash(data);
@ -506,6 +453,6 @@ namespace Luski.net
} }
} }
return datasplitout; return datasplitout;
}*/ }
} }
} }*/

View File

@ -1,6 +1,6 @@
namespace Luski.net.Enums; namespace Luski.net.Enums;
public enum ServerCacheMode : byte public enum CacheMode : byte
{ {
None, None,
Encrypted, Encrypted,

View File

@ -0,0 +1,12 @@
namespace Luski.net.Enums;
public enum StorageDirectory : byte
{
ServerInfo,
ServerAssets,
ChannelKeys,
ServerKeys,
Avatars,
ChannelIcons,
Messages
}

View File

@ -0,0 +1,24 @@
using System.Text.Json.Serialization;
using Luski.net.Enums;
namespace Luski.net.JsonTypes;
public class ServerStorageInfo
{
[JsonInclude]
[JsonPropertyName("cache_mode")]
public CacheMode CacheMode { get; set; } = CacheMode.Encrypted;
[JsonInclude]
[JsonPropertyName("prevent_deletion")]
public bool DontDelete { get; set; } = false;
}
[JsonSerializable(typeof(ServerStorageInfo))]
[JsonSourceGenerationOptions(
GenerationMode = JsonSourceGenerationMode.Default,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
WriteIndented = true)]
internal partial class ServerStorageInfoContext : JsonSerializerContext
{
}

View File

@ -13,7 +13,7 @@
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl> <RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
<IncludeSymbols>True</IncludeSymbols> <IncludeSymbols>True</IncludeSymbols>
<FileVersion>1.0.0</FileVersion> <FileVersion>1.0.0</FileVersion>
<Version>1.1.3-alpha24</Version> <Version>1.1.3-alpha25</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -13,47 +13,46 @@ using Luski.net.Enums;
using Luski.net.JsonTypes; using Luski.net.JsonTypes;
using Luski.net.JsonTypes.WSS; using Luski.net.JsonTypes.WSS;
using Luski.net.Structures.Main; using Luski.net.Structures.Main;
using Luski.net.Structures.Public;
using WebSocketSharp; using WebSocketSharp;
namespace Luski.net; namespace Luski.net;
public partial class MainServer public partial class MainServer
{ {
public void Login(string Email, string Password, System.Threading.CancellationToken CancellationToken) public void Login(string Username, string Password, CancellationToken CancellationToken)
{ {
Both(Email, Password, CancellationToken); Both(Username, Password, CancellationToken);
} }
public void CreateAccount(string Email, string Password, string Username, string PFP, System.Threading.CancellationToken CancellationToken) public void CreateAccount(string Username, string Password, string Displayname, string PFP, CancellationToken CancellationToken)
{ {
Both(Email, Password, CancellationToken, Username, PFP); Both(Username, Password, CancellationToken, Displayname, PFP);
} }
private void Both(string Email, string Password, System.Threading.CancellationToken CancellationToken, string? Username = null, string? pfp = null) private void Both(string Username, string Password, CancellationToken CancellationToken, string? Displayname = null, string? pfp = null)
{ {
if (!ClientEncryption.Generating) if (!EncryptionHandler.Generating)
{ {
ClientEncryption.GenerateKeys(); EncryptionHandler.GenerateKeys();
} }
while (!ClientEncryption.Generated) { } while (!EncryptionHandler.Generated) { }
login = true; login = true;
Login json; Login json;
List<KeyValuePair<string, string?>> heads = new() List<KeyValuePair<string, string?>> heads = new()
{ {
new("key", ClientEncryption.MyPublicKey), new("key", EncryptionHandler.MyPublicKey),
new("username", Convert.ToBase64String(Encryption.RSA.Encrypt(Email, ClientEncryption.MyPublicKey, EncoderType.UTF8))), new("username", Convert.ToBase64String(Encryption.RSA.Encrypt(Username, EncryptionHandler.MyPublicKey, EncoderType.UTF8))),
new("password", ClientEncryption.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password))) new("password", EncryptionHandler.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password)))
}; };
if (File.Exists("LastPassVer.txt") && int.TryParse(File.ReadAllText("LastPassVer.txt"), out int lpv) && lpv < ClientEncryption.PasswordVersion && lpv >= 0) if (File.Exists("LastPassVer.txt") && int.TryParse(File.ReadAllText("LastPassVer.txt"), out int lpv) && lpv < EncryptionHandler.PasswordVersion && lpv >= 0)
{ {
heads.Add(new("old_password", ClientEncryption.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password), lpv))); heads.Add(new("old_password", EncryptionHandler.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password), lpv)));
heads.Add(new("old_version", lpv.ToString())); heads.Add(new("old_version", lpv.ToString()));
} }
if (pfp is not null) if (pfp is not null)
{ {
heads.Add(new("username", Username)); heads.Add(new("username", Displayname));
json = SendServer( json = SendServer(
"CreateAccount", "CreateAccount",
pfp, pfp,
@ -70,7 +69,7 @@ public partial class MainServer
heads.ToArray()).Result; heads.ToArray()).Result;
} }
if (json.Error is not null) throw new Exception($"Luski appears to be down at the current moment: {json.ErrorMessage}"); if (json.Error is not null) throw new Exception($"Luski appears to be down at the current moment: {json.ErrorMessage}");
if (ClientEncryption.ofkey is null || ClientEncryption.outofkey is null) throw new Exception("Something went wrong generating the offline keys"); if (EncryptionHandler.OfflinePrivateKey is null || EncryptionHandler.OfflinePublicKey is null) throw new Exception("Something went wrong generating the offline keys");
login = false; login = false;
if (json is not null && json.Error is null) if (json is not null && json.Error is null)
{ {
@ -106,31 +105,9 @@ public partial class MainServer
} }
Console.WriteLine("User got"); Console.WriteLine("User got");
Console.WriteLine("Insert"); Console.WriteLine("Insert");
//User.Email = Email;
_ = UpdateStatus(UserStatus.Online, CancellationToken); _ = UpdateStatus(UserStatus.Online, CancellationToken);
Console.WriteLine("stat"); Console.WriteLine("stat");
try EncryptionHandler.Hash = EncryptionHandler.LocalPasswordEncrypt(Encoding.UTF8.GetBytes(Username.ToLower() + Password));
{
ClientEncryption.pw = Email.ToLower() + Password;
_ = ClientEncryption.File.GetOfflineKey();
}
catch
{
try
{
ClientEncryption.pw = Email + Password;
var temp222 = ClientEncryption.File.LuskiDataFile.GetDefualtDataFile();
ClientEncryption.pw = Email.ToLower() + Password;
if (temp222 is not null) temp222.Save("key.lsk", ClientEncryption.pw);
}
catch
{
Token = null;
Error = null;
ServerOut.Close();
throw new Exception("The key file you have is getting the wrong pasword. Type your Email in the same way you creaated your account to fix this error.");
}
}
Console.WriteLine("req offline"); Console.WriteLine("req offline");
OfflineData offlinedata = GetFromServer("Keys/GetOfflineData", OfflineDataContext.Default.OfflineData, CancellationToken).Result; OfflineData offlinedata = GetFromServer("Keys/GetOfflineData", OfflineDataContext.Default.OfflineData, CancellationToken).Result;
if (offlinedata.Data is not null && offlinedata.Data.Any()) Console.WriteLine(offlinedata.Data); if (offlinedata.Data is not null && offlinedata.Data.Any()) Console.WriteLine(offlinedata.Data);
@ -145,23 +122,37 @@ public partial class MainServer
{ {
Console.WriteLine(okd.channel); Console.WriteLine(okd.channel);
Console.WriteLine(okd.key); Console.WriteLine(okd.key);
ClientEncryption.File.Channels.AddKey(okd.channel, Encoding.UTF8.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(okd.key), ClientEncryption.File.GetOfflineKey()))); Storage.SetResourceKey(
StorageDirectory.ChannelKeys,
okd.channel.ToString(),
EncryptionHandler.Hash,
Encoding.UTF8.GetString(
Encryption.RSA.Decrypt(
Convert.FromBase64String(okd.key),
Storage.GetResourceKey(
StorageDirectory.ServerKeys,
"pkey",
EncryptionHandler.Hash
)
)
)
);
} }
} }
} }
Console.WriteLine("lpv"); Console.WriteLine("lpv");
System.IO.File.WriteAllText("LastPassVer.txt", ClientEncryption.PasswordVersion.ToString()); System.IO.File.WriteAllText("LastPassVer.txt", EncryptionHandler.PasswordVersion.ToString());
ClientEncryption.File.SetOfflineKey(ClientEncryption.ofkey); Storage.SetResourceKey(StorageDirectory.ServerKeys, "pkey", EncryptionHandler.Hash, EncryptionHandler.OfflinePrivateKey);
using HttpClient setkey = new(); using HttpClient setkey = new();
setkey.DefaultRequestHeaders.Add("token", Token); setkey.DefaultRequestHeaders.Add("token", Token);
_ = setkey.PostAsync($"https://{Domain}/{ApiVersion}/Keys/SetOfflineKey", new StringContent(ClientEncryption.outofkey)).Result; _ = setkey.PostAsync($"https://{Domain}/{ApiVersion}/Keys/SetOfflineKey", new StringContent(EncryptionHandler.OfflinePublicKey)).Result;
//_ = User.Channels; //_ = User.Channels;
foreach (var ch in chans) foreach (var ch in chans)
{ {
_ = ch.Members; _ = ch.Members;
} }
ClientEncryption.outofkey = null; EncryptionHandler.OfflinePublicKey = null;
ClientEncryption.ofkey = null; EncryptionHandler.OfflinePrivateKey = null;
} }
else throw new Exception(json?.ErrorMessage); else throw new Exception(json?.ErrorMessage);
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using JacobTechEncryption; using JacobTechEncryption;
@ -46,7 +47,8 @@ public partial class MainServer
MainSocketMessage? m = JsonSerializer.Deserialize<MainSocketMessage>(e.Data); MainSocketMessage? m = JsonSerializer.Deserialize<MainSocketMessage>(e.Data);
if (m is not null) if (m is not null)
{ {
m.decrypt(ClientEncryption.File.Channels.GetKey(m.ChannelID), CancellationToken.None); m.decrypt(Storage.GetResourceKey(StorageDirectory.ChannelKeys, m.ChannelID.ToString(),
EncryptionHandler.Hash), CancellationToken.None);
_ = MessageReceived.Invoke(m); _ = MessageReceived.Invoke(m);
} }
} }
@ -94,8 +96,19 @@ public partial class MainServer
{ {
KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data); KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data);
if (KE is not null) if (KE is not null)
ClientEncryption.File.Channels.AddKey(KE.channel, {
ClientEncryption.Encoder.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(KE.key), ClientEncryption.ofkey))); Storage.SetResourceKey(
StorageDirectory.ChannelKeys,
KE.channel.ToString(),
EncryptionHandler.Hash,
Encoding.UTF8.GetString(
Encryption.RSA.Decrypt(
Convert.FromBase64String(KE.key),
EncryptionHandler.myPrivateKey
)
)
);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -5,6 +5,7 @@ using System.Text.Json.Serialization.Metadata;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Luski.net.Enums; using Luski.net.Enums;
using Luski.net.Enums.Main;
using Luski.net.Interfaces; using Luski.net.Interfaces;
using Luski.net.JsonTypes.BaseTypes; using Luski.net.JsonTypes.BaseTypes;
using Luski.net.JsonTypes.HTTP; using Luski.net.JsonTypes.HTTP;
@ -67,6 +68,8 @@ public partial class MainServer : Server
chans.Remove(p); chans.Remove(p);
} }
} }
request.Server = this;
chans.Add(request); chans.Add(request);
return request; return request;
} }
@ -88,6 +91,9 @@ public partial class MainServer : Server
case MainSocketAppUser: case MainSocketAppUser:
user = (GetUser(UserID, MainSocketAppUserContext.Default.MainSocketAppUser, CancellationToken).Result as Tuser)!; user = (GetUser(UserID, MainSocketAppUserContext.Default.MainSocketAppUser, CancellationToken).Result as Tuser)!;
break; break;
case MainSocketRemoteUser:
user = (GetUser(UserID, MainSocketRemoteUserContext.Default.MainSocketRemoteUser, CancellationToken).Result as Tuser)!;
break;
case MainSocketUserBase: case MainSocketUserBase:
user = (GetUser(UserID, MainSocketUserBaseContext.Default.MainSocketUserBase, CancellationToken).Result as Tuser)!; user = (GetUser(UserID, MainSocketUserBaseContext.Default.MainSocketUserBase, CancellationToken).Result as Tuser)!;
break; break;
@ -110,11 +116,16 @@ public partial class MainServer : Server
message = await GetFromServer("socketmessage", message = await GetFromServer("socketmessage",
MainSocketMessageContext.Default.MainSocketMessage, MainSocketMessageContext.Default.MainSocketMessage,
CancellationToken, CancellationToken,
new System.Collections.Generic.KeyValuePair<string, string?>("msg_id", id.ToString())); new KeyValuePair<string, string?>("msg_id", id.ToString()));
break; break;
} }
} }
if (message is not null) return message;
if (message is not null)
{
message.Server = this;
return message;
}
throw new Exception("Server did not return a message"); throw new Exception("Server did not return a message");
} }
@ -143,6 +154,16 @@ public partial class MainServer : Server
if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId)) if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId))
{ {
Tuser temp = poeople.Where(s => s is Tuser && s.Id == UserId).Cast<Tuser>().FirstOrDefault()!; Tuser temp = poeople.Where(s => s is Tuser && s.Id == UserId).Cast<Tuser>().FirstOrDefault()!;
if (temp is MainSocketRemoteUser && (temp as MainSocketRemoteUser)!.Channel == null)
{
foreach (MainSocketDMChannel chan in chans.Where(s => s is MainSocketDMChannel).Cast<MainSocketDMChannel>())
{
if (chan.Type == ChannelType.DM && chan.Id != 0 && chan.MemberIdList is not null)
{
if (chan.MemberIdList.Any(s => s == UserId)) (temp as MainSocketRemoteUser)!.Channel = chan;
}
}
}
return temp; return temp;
} }
while (true) while (true)
@ -165,6 +186,18 @@ public partial class MainServer : Server
poeople.Remove(p); poeople.Remove(p);
} }
} }
user.Server = this;
if (user is MainSocketRemoteUser && (user as MainSocketRemoteUser)!.Channel == null)
{
foreach (MainSocketDMChannel chan in chans.Where(s => s is MainSocketDMChannel).Cast<MainSocketDMChannel>())
{
if (chan.Type == ChannelType.DM && chan.Id != 0 && chan.MemberIdList is not null)
{
if (chan.MemberIdList.Any(s => s == UserId)) (user as MainSocketRemoteUser)!.Channel = chan;
}
}
}
poeople.Add(user); poeople.Add(user);
return user; return user;
} }

View File

@ -15,50 +15,10 @@ public partial class Server
{ {
public ServerType ServerType { get; internal set; } = ServerType.Public; public ServerType ServerType { get; internal set; } = ServerType.Public;
public string Domain { get; internal set; } = default!; public string Domain { get; internal set; } = default!;
public ServerCacheMode CacheMode { get; set; } = ServerCacheMode.None;
public string ApiVersion { get; internal set; } = "v1"; public string ApiVersion { get; internal set; } = "v1";
internal WebSocket? ServerOut; internal WebSocket? ServerOut;
internal string? Token = null, Error = null, gen = null; internal string? Token = null, Error = null, gen = null;
internal bool CanRequest = false, login = false; internal bool CanRequest = false, login = false;
internal List<IUser> poeople = new(); internal List<IUser> poeople = new();
public long UserID { get; internal set; } = 0;
internal List<MainSocketChannel> chans { get; set; } = new(); internal List<MainSocketChannel> chans { get; set; } = new();
public string Cache
{
get
{
if (gen is null)
{
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
string path = JT + "/Luski/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
path += "Data/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
path += UserID + "/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
path += "Cache/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
path += Path.GetRandomFileName() + "/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
gen = path;
}
if (!Directory.Exists($"{gen}/avatars")) Directory.CreateDirectory($"{gen}/avatars");
if (!Directory.Exists($"{gen}/channels")) Directory.CreateDirectory($"{gen}/channels");
return gen;
}
}
internal static string JT
{
get
{
string tmp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "JacobTech");
if (OperatingSystem.IsLinux())
{
tmp = Path.Combine(Environment.GetEnvironmentVariable("HOME")!, ".config/");
tmp += "JacobTech";
}
return tmp;
}
}
} }

View File

@ -10,12 +10,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Luski.net.Enums; using Luski.net.Enums;
using Luski.net.Interfaces; using Luski.net.Interfaces;
using Luski.net.JsonTypes;
using Luski.net.JsonTypes.BaseTypes; using Luski.net.JsonTypes.BaseTypes;
using Luski.net.JsonTypes.HTTP;
using Luski.net.Structures;
using Luski.net.Structures.Main;
using Luski.net.Structures.Public;
using File = System.IO.File; using File = System.IO.File;
namespace Luski.net; namespace Luski.net;
@ -23,16 +18,17 @@ namespace Luski.net;
public partial class Server public partial class Server
{ {
internal Server() internal Server()
{ } {
}
public ServerEncryption EncryptionHandler { get; internal set; } = null!;
public ServerStorage Storage { get; internal set; } = null!;
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken) public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
{ {
if (Cache != null) bool isc = File.Exists(Storage.GetStorageDirectory(StorageDirectory.ServerAssets) + "Icon");
{ if (!isc) await GetFromServer($"socketserver/Avatar/", Storage.GetStorageDirectory(StorageDirectory.ServerAssets) + "Icon", CancellationToken);
bool isc = File.Exists($"{Cache}/servers/{Domain}"); return Storage.GetResourceBytes(StorageDirectory.ServerAssets, "Icon");
if (!isc) await GetFromServer($"socketserver/Avatar/", $"{Cache}/servers/{Domain}-{ApiVersion}", CancellationToken);
}
return File.ReadAllBytes($"{Cache}/servers/{Domain}");
} }
public void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS public void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS

View File

@ -0,0 +1,56 @@
using System;
using System.Security.Cryptography;
using JacobTechEncryption;
namespace Luski.net;
public class ServerEncryption
{
internal bool Generating, Generated;
internal string ServerPublicKey = "", MyPublicKey = "", myPrivateKey = "", OfflinePrivateKey = "", OfflinePublicKey = "";
internal byte[] Hash = default!;
internal ServerEncryption(string Domain)
{
//TODO Get server p key
}
internal int PasswordVersion = 0;
internal byte[] LocalPasswordEncrypt(byte[] Password) => LocalPasswordEncrypt(Password, PasswordVersion);
internal string RemotePasswordEncrypt(byte[] Password) => RemotePasswordEncrypt(Password, PasswordVersion);
internal byte[] LocalPasswordEncrypt(byte[] Password, int PasswordVersion)
{
return PasswordVersion switch
{
0 => SHA256.Create().ComputeHash(Password),
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
};
}
internal string RemotePasswordEncrypt(byte[] Password, int PasswordVersion)
{
return PasswordVersion switch
{
0 => Convert.ToBase64String(Encryption.RSA.Encrypt(LocalPasswordEncrypt(Password, PasswordVersion), ServerPublicKey)),
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
};
}
public void GenerateKeys()
{
if (!Generating)
{
Generating = true;
GenerateNewKeys(out MyPublicKey, out myPrivateKey);
GenerateNewKeys(out OfflinePublicKey, out OfflinePrivateKey);
Generated = true;
}
}
public static void GenerateNewKeys(out string Public, out string Private, int KeySize = 4096)
{
using RSACryptoServiceProvider r = new(KeySize);
Private = r.ToXmlString(true);
Public = r.ToXmlString(false);
}
}

116
Luski.net/ServerStorage.cs Normal file
View File

@ -0,0 +1,116 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using JacobTechEncryption;
using Luski.net.Enums;
using Luski.net.JsonTypes;
namespace Luski.net;
public class ServerStorage
{
public static readonly string[] Directories = new[]
{
"Info",
"Assets",
"Channels/Keys",
"Keys",
"Avatars",
"Channels/Icons",
"Channels/Messages"
};
private static readonly int[] CantDelete = new[]
{
(int)StorageDirectory.ChannelKeys,
(int)StorageDirectory.ServerKeys
};
internal ServerStorage(string Domain)
{
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
Location = JT + "/Luski/";
if (!Directory.Exists(Location)) Directory.CreateDirectory(Location);
Location += "Storage/";
if (!Directory.Exists(Location)) Directory.CreateDirectory(Location);
Location += "Servers/";
if (!Directory.Exists(Location)) Directory.CreateDirectory(Location);
Location += Domain+ "/";
if (!Directory.Exists(Location)) Directory.CreateDirectory(Location);
if (!File.Exists(Location + "storage.json")) File.WriteAllText(Location + "storage.json", JsonSerializer.Serialize(new ServerStorageInfo(),ServerStorageInfoContext.Default.ServerStorageInfo));
ServerStorageInfo info = JsonSerializer.Deserialize(File.ReadAllText(Location + "storage.json"),
ServerStorageInfoContext.Default.ServerStorageInfo)!;
CacheMode = info.CacheMode;
for (int i = 0; i < Directories.Length; i++)
{
string full = Location;
string[] spl = Directories[i].Split('/');
if (!info.DontDelete && !CantDelete.Contains(i))
{
try
{
if (Directory.Exists(full + spl[0])) Directory.Delete(full + spl[0], true);
}
catch
{
// ignored
}
}
foreach (string d in spl)
{
full += d + "/";
if (!Directory.Exists(full)) Directory.CreateDirectory(full);
}
}
}
public string Location { get; internal set; }
public string GetStorageDirectory(StorageDirectory Directory)
{
return Location + Directories[(byte)Directory] + "/";
}
public string GetResourceKey(StorageDirectory Directory, string Resource, string Key)
{
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Key));
}
public string GetResourceKey(StorageDirectory Directory, string Resource, byte[] Key)
{
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Encoding.UTF8.GetString(Key)));
}
public void SetResourceKey(StorageDirectory Directory, string Resource, string Key, string value)
{
File.WriteAllBytes(GetStorageDirectory(Directory) + Resource, Encryption.AES.Encrypt(Encoding.UTF8.GetBytes(value), Key));
}
public void SetResourceKey(StorageDirectory Directory, string Resource, byte[] Key, string value)
{
File.WriteAllBytes(GetStorageDirectory(Directory) + Resource, Encryption.AES.Encrypt(Encoding.UTF8.GetBytes(value), Encoding.UTF8.GetString(Key)));
}
public byte[] GetResourceBytes(StorageDirectory Directory, string Resource)
{
return File.ReadAllBytes(Location + Directories[(byte)Directory] + "/" + Resource);
}
public CacheMode CacheMode { get; internal set; }
internal static string JT
{
get
{
string tmp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "JacobTech");
if (OperatingSystem.IsLinux())
{
tmp = Path.Combine(Environment.GetEnvironmentVariable("HOME")!, ".config/");
tmp += "JacobTech";
}
return tmp;
}
}
}

View File

@ -18,7 +18,7 @@ namespace Luski.net.Structures;
public class File : IncomingHTTP public class File : IncomingHTTP
{ {
public IServer Server { get; internal set; } public MainServer Server { get; internal set; }
[JsonInclude] [JsonInclude]
[JsonPropertyName("name")] [JsonPropertyName("name")]
public string Name { get; internal set; } = default!; public string Name { get; internal set; } = default!;
@ -35,6 +35,8 @@ public class File : IncomingHTTP
public async Task DownloadBytes(string Loc, long key, CancellationToken CancellationToken) public async Task DownloadBytes(string Loc, long key, CancellationToken CancellationToken)
{ {
//TODO make better
//using HttpClient web = new(); //using HttpClient web = new();
//web.DefaultRequestHeaders.Add("token", Server.Token); //web.DefaultRequestHeaders.Add("token", Server.Token);
//web.DefaultRequestHeaders.Add("id", id.ToString()); //web.DefaultRequestHeaders.Add("id", id.ToString());
@ -42,7 +44,7 @@ public class File : IncomingHTTP
string path = Path.GetTempFileName(); string path = Path.GetTempFileName();
await Server.GetFromServer($"SocketMessage/GetFile/{Id}", path, CancellationToken); await Server.GetFromServer($"SocketMessage/GetFile/{Id}", path, CancellationToken);
string Key = (key == 0 ? ClientEncryption.MyPublicKey : ClientEncryption.File.Channels.GetKey(key))!; string Key = (key == 0 ? Server.EncryptionHandler.MyPublicKey : "") ;// ClientEncryption.File.Channels.GetKey(key))!;
Encryption.AES.DecryptToFile(System.IO.File.ReadAllBytes(path), Key, Loc); Encryption.AES.DecryptToFile(System.IO.File.ReadAllBytes(path), Key, Loc);
/* /*
if (request is not null && request.Error is not null) if (request is not null && request.Error is not null)

View File

@ -70,7 +70,8 @@ public class MainSocketChannel : IncomingHTTP
} }
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 50) * 2.0)); int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 50) * 2.0));
if (num == 0) num = 1; if (num == 0) num = 1;
string? lkey = ClientEncryption.File.Channels.GetKey(Id); string lkey = Server.Storage.GetResourceKey(StorageDirectory.ChannelKeys, Id.ToString(),
Server.EncryptionHandler.Hash);
Parallel.ForEach(Members, new ParallelOptions() Parallel.ForEach(Members, new ParallelOptions()
{ {
MaxDegreeOfParallelism = num MaxDegreeOfParallelism = num
@ -95,7 +96,9 @@ public class MainSocketChannel : IncomingHTTP
} }
internal Task StartKeyProcessAsync(CancellationToken CancellationToken) internal Task StartKeyProcessAsync(CancellationToken CancellationToken)
{/* {
//TODO code key exchange
/*
ClientEncryption.GenerateNewKeys(out string Public, out string Private); ClientEncryption.GenerateNewKeys(out string Public, out string Private);
Key = Public; Key = Public;
HttpResponseMessage b; HttpResponseMessage b;

View File

@ -18,6 +18,7 @@ public class MainSocketRemoteUser : MainSocketUserBase
[JsonPropertyName("friend_status")] [JsonPropertyName("friend_status")]
[JsonInclude] [JsonInclude]
public FriendStatus FriendStatus { get; internal set; } = default!; public FriendStatus FriendStatus { get; internal set; } = default!;
public MainSocketDMChannel Channel { get; internal set; }
internal MainSocketRemoteUser Clone() internal MainSocketRemoteUser Clone()
{ {

View File

@ -27,12 +27,9 @@ public class MainSocketTextChannel : MainSocketChannel
if (Type == ChannelType.DM) return Members.First().GetAvatar(CancellationToken).Result; if (Type == ChannelType.DM) return Members.First().GetAvatar(CancellationToken).Result;
else else
{ {
if (Server.Cache != null) 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);
bool isc = System.IO.File.Exists($"{Server.Cache}/channels/{Id}"); return Server.Storage.GetResourceBytes(StorageDirectory.ChannelIcons, Id.ToString());
if (!isc) await Server.GetFromServer($"SocketChannel/GetPicture/{Id}", $"{Server.Cache}/channels/{Id}", CancellationToken);
}
return System.IO.File.ReadAllBytes($"{Server.Cache}/channels/{Id}");
} }
} }
@ -59,7 +56,8 @@ public class MainSocketTextChannel : MainSocketChannel
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0)); int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0));
if (num == 0) num = 1; if (num == 0) num = 1;
string? key = ClientEncryption.File.Channels.GetKey(Id); string key = Server.Storage.GetResourceKey(StorageDirectory.ChannelKeys, Id.ToString(),
Server.EncryptionHandler.Hash);
if (data is null) throw new Exception("Invalid data from server"); if (data is null) throw new Exception("Invalid data from server");
if (data.Messages is null) data.Messages = Array.Empty<MainSocketMessage>(); if (data.Messages is null) data.Messages = Array.Empty<MainSocketMessage>();
Parallel.ForEach(data.Messages, new ParallelOptions() Parallel.ForEach(data.Messages, new ParallelOptions()
@ -105,7 +103,8 @@ public class MainSocketTextChannel : MainSocketChannel
{ {
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0)); int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0));
if (num == 0) num = 1; if (num == 0) num = 1;
string? key = ClientEncryption.File.Channels.GetKey(Id); string key = Server.Storage.GetResourceKey(StorageDirectory.ChannelKeys, Id.ToString(),
Server.EncryptionHandler.Hash);
if (data.Messages is null) data.Messages = Array.Empty<MainSocketMessage>(); if (data.Messages is null) data.Messages = Array.Empty<MainSocketMessage>();
Parallel.ForEach(data.Messages, new ParallelOptions() Parallel.ForEach(data.Messages, new ParallelOptions()
{ {
@ -140,8 +139,8 @@ public class MainSocketTextChannel : MainSocketChannel
public async Task<Task> SendMessage(string Message, CancellationToken CancellationToken, params File?[] Files) public async Task<Task> SendMessage(string Message, CancellationToken CancellationToken, params File?[] Files)
{ {
string key = ClientEncryption.File.Channels.GetKey(Id); string key = Server.Storage.GetResourceKey(StorageDirectory.ChannelKeys, Id.ToString(),
if (Id == 0) key = "";//ClientEncryption.ServerPublicKey; Server.EncryptionHandler.Hash);
JsonTypes.HTTP.Message m = new() JsonTypes.HTTP.Message m = new()
{ {
Context = Convert.ToBase64String(Encryption.RSA.Encrypt(Message, key, EncoderType.UTF8)), Context = Convert.ToBase64String(Encryption.RSA.Encrypt(Message, key, EncoderType.UTF8)),

View File

@ -24,12 +24,9 @@ public class MainSocketUserBase : IncomingHTTP, IUser
public PictureType PictureType { get; internal set; } = default!; public PictureType PictureType { get; internal set; } = default!;
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken) public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
{ {
if (Server.Cache != null) bool isc = System.IO.File.Exists(Server.Storage.GetStorageDirectory(StorageDirectory.Avatars) + Id.ToString());
{ if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", Server.Storage.GetStorageDirectory(StorageDirectory.Avatars) + Id.ToString(), CancellationToken);
bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}"); return Server.Storage.GetResourceBytes(StorageDirectory.Avatars, Id.ToString());
if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}", CancellationToken);
}
return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
} }
public Task<long> GetUserKey(CancellationToken CancellationToken) public Task<long> GetUserKey(CancellationToken CancellationToken)

View File

@ -24,12 +24,9 @@ public class PublicSocketUserBase : IncomingHTTP, IUser
public PictureType PictureType { get; internal set; } = default!; public PictureType PictureType { get; internal set; } = default!;
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken) public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
{ {
if (Server.Cache != null) bool isc = System.IO.File.Exists(Server.Storage.GetStorageDirectory(StorageDirectory.Avatars) + Id.ToString());
{ if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", Server.Storage.GetStorageDirectory(StorageDirectory.Avatars) + Id.ToString(), CancellationToken);
bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}"); return Server.Storage.GetResourceBytes(StorageDirectory.Avatars, Id.ToString());
if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}", CancellationToken);
}
return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
} }
public Task<long> GetUserKey(CancellationToken CancellationToken) public Task<long> GetUserKey(CancellationToken CancellationToken)