dev #1
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Luski.net.Enums;
|
||||
using Luski.net.Structures.Main;
|
||||
using Luski.net.Structures.Public;
|
||||
|
||||
@ -19,6 +20,9 @@ public class API
|
||||
{
|
||||
Domain = Domain,
|
||||
ApiVersion = Version,
|
||||
Storage = new(Domain),
|
||||
EncryptionHandler = new(Domain),
|
||||
ServerType = ServerType.Public
|
||||
};
|
||||
InternalServers.Add(s);
|
||||
return s;
|
||||
@ -30,6 +34,9 @@ public class API
|
||||
{
|
||||
Domain = Domain,
|
||||
ApiVersion = Version,
|
||||
Storage = new(Domain),
|
||||
EncryptionHandler = new(Domain),
|
||||
ServerType = ServerType.Main
|
||||
};
|
||||
return MainServer;
|
||||
}
|
||||
|
@ -1,51 +1,19 @@
|
||||
using Luski.net.Enums;
|
||||
using System;
|
||||
/*using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using JacobTechEncryption;
|
||||
|
||||
namespace Luski.net
|
||||
{
|
||||
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 = "";
|
||||
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
|
||||
{
|
||||
{/*
|
||||
internal static void SetOfflineKey(string key)
|
||||
{
|
||||
MakeFile("Server.GetKeyFilePath", pw);
|
||||
@ -54,11 +22,7 @@ namespace Luski.net
|
||||
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()
|
||||
{
|
||||
@ -67,6 +31,12 @@ namespace Luski.net
|
||||
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)
|
||||
{
|
||||
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
|
||||
@ -112,14 +82,14 @@ namespace Luski.net
|
||||
|
||||
public static class Channels
|
||||
{
|
||||
public static string GetKey(long channel)
|
||||
private static string GetKey(long channel)
|
||||
{
|
||||
LuskiDataFile? fileLayout;
|
||||
IEnumerable<ChannelLayout>? lis;
|
||||
try
|
||||
{
|
||||
#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.
|
||||
MakeFile("Server.GetKeyFilePath", pw);
|
||||
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw));
|
||||
@ -144,7 +114,7 @@ namespace Luski.net
|
||||
try
|
||||
{
|
||||
#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.
|
||||
MakeFile("Server.GetKeyFilePathBr(branch.ToString())", pw);
|
||||
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("", pw));
|
||||
@ -273,8 +243,7 @@ namespace Luski.net
|
||||
public string key { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
/*
|
||||
public class AES
|
||||
public class AES
|
||||
{
|
||||
public static string Encrypt(string path, string Password)
|
||||
{
|
||||
@ -301,12 +270,10 @@ namespace Luski.net
|
||||
msEncrypt.Dispose();
|
||||
return p;
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
string p = Path.GetTempFileName();
|
||||
string p = Path.GetTempFileName();
|
||||
byte[] salt = new byte[100];
|
||||
RNGCryptoServiceProvider provider = new();
|
||||
provider.GetBytes(salt);
|
||||
@ -378,27 +345,7 @@ namespace Luski.net
|
||||
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)
|
||||
{
|
||||
return SHA256.Create().ComputeHash(data);
|
||||
@ -506,6 +453,6 @@ namespace Luski.net
|
||||
}
|
||||
}
|
||||
return datasplitout;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Luski.net.Enums;
|
||||
|
||||
public enum ServerCacheMode : byte
|
||||
public enum CacheMode : byte
|
||||
{
|
||||
None,
|
||||
Encrypted,
|
12
Luski.net/Enums/StorageDirectory.cs
Normal file
12
Luski.net/Enums/StorageDirectory.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Luski.net.Enums;
|
||||
|
||||
public enum StorageDirectory : byte
|
||||
{
|
||||
ServerInfo,
|
||||
ServerAssets,
|
||||
ChannelKeys,
|
||||
ServerKeys,
|
||||
Avatars,
|
||||
ChannelIcons,
|
||||
Messages
|
||||
}
|
24
Luski.net/JsonTypes/ServerStorageInfo.cs
Normal file
24
Luski.net/JsonTypes/ServerStorageInfo.cs
Normal 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
|
||||
{
|
||||
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<FileVersion>1.0.0</FileVersion>
|
||||
<Version>1.1.3-alpha24</Version>
|
||||
<Version>1.1.3-alpha25</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -13,47 +13,46 @@ using Luski.net.Enums;
|
||||
using Luski.net.JsonTypes;
|
||||
using Luski.net.JsonTypes.WSS;
|
||||
using Luski.net.Structures.Main;
|
||||
using Luski.net.Structures.Public;
|
||||
using WebSocketSharp;
|
||||
|
||||
namespace Luski.net;
|
||||
|
||||
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 json;
|
||||
List<KeyValuePair<string, string?>> heads = new()
|
||||
{
|
||||
new("key", ClientEncryption.MyPublicKey),
|
||||
new("username", Convert.ToBase64String(Encryption.RSA.Encrypt(Email, ClientEncryption.MyPublicKey, EncoderType.UTF8))),
|
||||
new("password", ClientEncryption.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password)))
|
||||
new("key", EncryptionHandler.MyPublicKey),
|
||||
new("username", Convert.ToBase64String(Encryption.RSA.Encrypt(Username, EncryptionHandler.MyPublicKey, EncoderType.UTF8))),
|
||||
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()));
|
||||
}
|
||||
if (pfp is not null)
|
||||
{
|
||||
heads.Add(new("username", Username));
|
||||
heads.Add(new("username", Displayname));
|
||||
json = SendServer(
|
||||
"CreateAccount",
|
||||
pfp,
|
||||
@ -70,7 +69,7 @@ public partial class MainServer
|
||||
heads.ToArray()).Result;
|
||||
}
|
||||
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;
|
||||
if (json is not null && json.Error is null)
|
||||
{
|
||||
@ -106,31 +105,9 @@ public partial class MainServer
|
||||
}
|
||||
Console.WriteLine("User got");
|
||||
Console.WriteLine("Insert");
|
||||
//User.Email = Email;
|
||||
_ = UpdateStatus(UserStatus.Online, CancellationToken);
|
||||
Console.WriteLine("stat");
|
||||
try
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
EncryptionHandler.Hash = EncryptionHandler.LocalPasswordEncrypt(Encoding.UTF8.GetBytes(Username.ToLower() + Password));
|
||||
Console.WriteLine("req offline");
|
||||
OfflineData offlinedata = GetFromServer("Keys/GetOfflineData", OfflineDataContext.Default.OfflineData, CancellationToken).Result;
|
||||
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.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");
|
||||
System.IO.File.WriteAllText("LastPassVer.txt", ClientEncryption.PasswordVersion.ToString());
|
||||
ClientEncryption.File.SetOfflineKey(ClientEncryption.ofkey);
|
||||
System.IO.File.WriteAllText("LastPassVer.txt", EncryptionHandler.PasswordVersion.ToString());
|
||||
Storage.SetResourceKey(StorageDirectory.ServerKeys, "pkey", EncryptionHandler.Hash, EncryptionHandler.OfflinePrivateKey);
|
||||
using HttpClient setkey = new();
|
||||
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;
|
||||
foreach (var ch in chans)
|
||||
{
|
||||
_ = ch.Members;
|
||||
}
|
||||
ClientEncryption.outofkey = null;
|
||||
ClientEncryption.ofkey = null;
|
||||
EncryptionHandler.OfflinePublicKey = null;
|
||||
EncryptionHandler.OfflinePrivateKey = null;
|
||||
}
|
||||
else throw new Exception(json?.ErrorMessage);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using JacobTechEncryption;
|
||||
@ -46,7 +47,8 @@ public partial class MainServer
|
||||
MainSocketMessage? m = JsonSerializer.Deserialize<MainSocketMessage>(e.Data);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -94,8 +96,19 @@ public partial class MainServer
|
||||
{
|
||||
KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data);
|
||||
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)
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using System.Text.Json.Serialization.Metadata;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Luski.net.Enums;
|
||||
using Luski.net.Enums.Main;
|
||||
using Luski.net.Interfaces;
|
||||
using Luski.net.JsonTypes.BaseTypes;
|
||||
using Luski.net.JsonTypes.HTTP;
|
||||
@ -67,6 +68,8 @@ public partial class MainServer : Server
|
||||
chans.Remove(p);
|
||||
}
|
||||
}
|
||||
|
||||
request.Server = this;
|
||||
chans.Add(request);
|
||||
return request;
|
||||
}
|
||||
@ -88,6 +91,9 @@ public partial class MainServer : Server
|
||||
case MainSocketAppUser:
|
||||
user = (GetUser(UserID, MainSocketAppUserContext.Default.MainSocketAppUser, CancellationToken).Result as Tuser)!;
|
||||
break;
|
||||
case MainSocketRemoteUser:
|
||||
user = (GetUser(UserID, MainSocketRemoteUserContext.Default.MainSocketRemoteUser, CancellationToken).Result as Tuser)!;
|
||||
break;
|
||||
case MainSocketUserBase:
|
||||
user = (GetUser(UserID, MainSocketUserBaseContext.Default.MainSocketUserBase, CancellationToken).Result as Tuser)!;
|
||||
break;
|
||||
@ -110,11 +116,16 @@ public partial class MainServer : Server
|
||||
message = await GetFromServer("socketmessage",
|
||||
MainSocketMessageContext.Default.MainSocketMessage,
|
||||
CancellationToken,
|
||||
new System.Collections.Generic.KeyValuePair<string, string?>("msg_id", id.ToString()));
|
||||
new KeyValuePair<string, string?>("msg_id", id.ToString()));
|
||||
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");
|
||||
}
|
||||
|
||||
@ -143,6 +154,16 @@ public partial class MainServer : Server
|
||||
if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId))
|
||||
{
|
||||
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;
|
||||
}
|
||||
while (true)
|
||||
@ -165,6 +186,18 @@ public partial class MainServer : Server
|
||||
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);
|
||||
return user;
|
||||
}
|
||||
|
@ -15,50 +15,10 @@ public partial class Server
|
||||
{
|
||||
public ServerType ServerType { get; internal set; } = ServerType.Public;
|
||||
public string Domain { get; internal set; } = default!;
|
||||
public ServerCacheMode CacheMode { get; set; } = ServerCacheMode.None;
|
||||
public string ApiVersion { get; internal set; } = "v1";
|
||||
internal WebSocket? ServerOut;
|
||||
internal string? Token = null, Error = null, gen = null;
|
||||
internal bool CanRequest = false, login = false;
|
||||
internal List<IUser> poeople = new();
|
||||
public long UserID { get; internal set; } = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,12 +10,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Luski.net.Enums;
|
||||
using Luski.net.Interfaces;
|
||||
using Luski.net.JsonTypes;
|
||||
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;
|
||||
|
||||
namespace Luski.net;
|
||||
@ -23,16 +18,17 @@ namespace Luski.net;
|
||||
public partial class Server
|
||||
{
|
||||
internal Server()
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
public ServerEncryption EncryptionHandler { get; internal set; } = null!;
|
||||
public ServerStorage Storage { get; internal set; } = null!;
|
||||
|
||||
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
|
||||
{
|
||||
if (Cache != null)
|
||||
{
|
||||
bool isc = File.Exists($"{Cache}/servers/{Domain}");
|
||||
if (!isc) await GetFromServer($"socketserver/Avatar/", $"{Cache}/servers/{Domain}-{ApiVersion}", CancellationToken);
|
||||
}
|
||||
return File.ReadAllBytes($"{Cache}/servers/{Domain}");
|
||||
bool isc = File.Exists(Storage.GetStorageDirectory(StorageDirectory.ServerAssets) + "Icon");
|
||||
if (!isc) await GetFromServer($"socketserver/Avatar/", Storage.GetStorageDirectory(StorageDirectory.ServerAssets) + "Icon", CancellationToken);
|
||||
return Storage.GetResourceBytes(StorageDirectory.ServerAssets, "Icon");
|
||||
}
|
||||
|
||||
public void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS
|
||||
|
56
Luski.net/ServerEncryption.cs
Normal file
56
Luski.net/ServerEncryption.cs
Normal 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
116
Luski.net/ServerStorage.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ namespace Luski.net.Structures;
|
||||
|
||||
public class File : IncomingHTTP
|
||||
{
|
||||
public IServer Server { get; internal set; }
|
||||
public MainServer Server { get; internal set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("name")]
|
||||
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)
|
||||
{
|
||||
//TODO make better
|
||||
|
||||
//using HttpClient web = new();
|
||||
//web.DefaultRequestHeaders.Add("token", Server.Token);
|
||||
//web.DefaultRequestHeaders.Add("id", id.ToString());
|
||||
@ -42,7 +44,7 @@ public class File : IncomingHTTP
|
||||
string path = Path.GetTempFileName();
|
||||
|
||||
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);
|
||||
/*
|
||||
if (request is not null && request.Error is not null)
|
||||
|
@ -70,7 +70,8 @@ public class MainSocketChannel : IncomingHTTP
|
||||
}
|
||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 50) * 2.0));
|
||||
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()
|
||||
{
|
||||
MaxDegreeOfParallelism = num
|
||||
@ -95,7 +96,9 @@ public class MainSocketChannel : IncomingHTTP
|
||||
}
|
||||
|
||||
internal Task StartKeyProcessAsync(CancellationToken CancellationToken)
|
||||
{/*
|
||||
{
|
||||
//TODO code key exchange
|
||||
/*
|
||||
ClientEncryption.GenerateNewKeys(out string Public, out string Private);
|
||||
Key = Public;
|
||||
HttpResponseMessage b;
|
||||
|
@ -18,6 +18,7 @@ public class MainSocketRemoteUser : MainSocketUserBase
|
||||
[JsonPropertyName("friend_status")]
|
||||
[JsonInclude]
|
||||
public FriendStatus FriendStatus { get; internal set; } = default!;
|
||||
public MainSocketDMChannel Channel { get; internal set; }
|
||||
|
||||
internal MainSocketRemoteUser Clone()
|
||||
{
|
||||
|
@ -27,12 +27,9 @@ public class MainSocketTextChannel : MainSocketChannel
|
||||
if (Type == ChannelType.DM) return Members.First().GetAvatar(CancellationToken).Result;
|
||||
else
|
||||
{
|
||||
if (Server.Cache != null)
|
||||
{
|
||||
bool isc = System.IO.File.Exists($"{Server.Cache}/channels/{Id}");
|
||||
if (!isc) await Server.GetFromServer($"SocketChannel/GetPicture/{Id}", $"{Server.Cache}/channels/{Id}", CancellationToken);
|
||||
}
|
||||
return System.IO.File.ReadAllBytes($"{Server.Cache}/channels/{Id}");
|
||||
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);
|
||||
return Server.Storage.GetResourceBytes(StorageDirectory.ChannelIcons, Id.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +56,8 @@ public class MainSocketTextChannel : MainSocketChannel
|
||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0));
|
||||
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.Messages is null) data.Messages = Array.Empty<MainSocketMessage>();
|
||||
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));
|
||||
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>();
|
||||
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)
|
||||
{
|
||||
string key = ClientEncryption.File.Channels.GetKey(Id);
|
||||
if (Id == 0) key = "";//ClientEncryption.ServerPublicKey;
|
||||
string key = Server.Storage.GetResourceKey(StorageDirectory.ChannelKeys, Id.ToString(),
|
||||
Server.EncryptionHandler.Hash);
|
||||
JsonTypes.HTTP.Message m = new()
|
||||
{
|
||||
Context = Convert.ToBase64String(Encryption.RSA.Encrypt(Message, key, EncoderType.UTF8)),
|
||||
|
@ -24,12 +24,9 @@ public class MainSocketUserBase : IncomingHTTP, IUser
|
||||
public PictureType PictureType { get; internal set; } = default!;
|
||||
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
|
||||
{
|
||||
if (Server.Cache != null)
|
||||
{
|
||||
bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}");
|
||||
if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}", CancellationToken);
|
||||
}
|
||||
return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
|
||||
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);
|
||||
return Server.Storage.GetResourceBytes(StorageDirectory.Avatars, Id.ToString());
|
||||
}
|
||||
|
||||
public Task<long> GetUserKey(CancellationToken CancellationToken)
|
||||
|
@ -24,12 +24,9 @@ public class PublicSocketUserBase : IncomingHTTP, IUser
|
||||
public PictureType PictureType { get; internal set; } = default!;
|
||||
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
|
||||
{
|
||||
if (Server.Cache != null)
|
||||
{
|
||||
bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}");
|
||||
if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}", CancellationToken);
|
||||
}
|
||||
return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
|
||||
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);
|
||||
return Server.Storage.GetResourceBytes(StorageDirectory.Avatars, Id.ToString());
|
||||
}
|
||||
|
||||
public Task<long> GetUserKey(CancellationToken CancellationToken)
|
Loading…
Reference in New Issue
Block a user