Luski.Net/Luski.net/Server.Storage.cs
JacobTech 0349745944 Alternate servers.
On load, the client can find alternate servers to connect to.
2023-08-25 12:07:36 -04:00

343 lines
11 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using JacobTechEncryption;
using JacobTechEncryption.Enums;
using Luski.net.Enums;
using Luski.net.JsonTypes;
using Luski.net.Structures;
using File = System.IO.File;
namespace Luski.net;
public class ServerStorage
{
public static readonly string[] Directories = new[]
{
"Info",
"Assets",
"Channels/Keys",
"Keys",
"Avatars",
"Channels/Icons",
"Channels/Messages",
"StorageInfo",
"Channels/Files"
};
private static readonly int[] CantDelete = new[]
{
(int)StorageDirectory.ChannelKeys,
(int)StorageDirectory.ServerKeys,
(int)StorageDirectory.StorageInfo
};
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.ToLower() + "/";
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));
RawInfo = JsonSerializer.Deserialize(File.ReadAllText(Location + "storage.json"),
ServerStorageInfoContext.Default.ServerStorageInfo)!;
CacheMode = RawInfo.CacheMode;
StorageID = RawInfo.StorageID;
for (int i = 0; i < Directories.Length; i++)
{
string full = Location;
string[] spl = Directories[i].Split('/');
foreach (string d in spl)
{
full += d + "/";
if (!Directory.Exists(full)) Directory.CreateDirectory(full);
}
}
}
internal void setid(long id)
{
StorageID = id;
RawInfo.StorageID = id;
File.WriteAllText(Location + "storage.json", JsonSerializer.Serialize(RawInfo,ServerStorageInfoContext.Default.ServerStorageInfo));
}
internal ServerStorageInfo RawInfo { get; }
public TResult GetJson<TResult>(StorageDirectory Directory, string Resource, bool CreateOnMissing, JsonTypeInfo<TResult> JsonInfo) where TResult : new()
{
string FilePath = GetResourceDirectory(Directory, Resource);
if (!File.Exists(FilePath))
{
TResult res = new();
File.WriteAllText(FilePath, JsonSerializer.Serialize(res, JsonInfo));
return res;
}
Stream s = GetResourceStream(FilePath);
return JsonSerializer.Deserialize(s, JsonInfo)!;
}
public byte[] UpdateStorage(byte[] OldPassword)
{
try
{
byte[] NewPassword = new byte[100];
byte[] lpk = GetResourceBytes(StorageDirectory.StorageInfo, "lpk");
OldPassword = Encryption.AES.Decrypt(OldPassword, lpk);
using (RandomNumberGenerator provider = RandomNumberGenerator.Create())
{
provider.GetBytes(NewPassword);
}
void UpdateDir(string Dir)
{
DirectoryInfo DI = new(Dir);
foreach (DirectoryInfo DIR in DI.GetDirectories())
{
UpdateDir(DIR.FullName);
}
foreach (FileInfo FI in DI.GetFiles())
{
byte[] raw = Array.Empty<byte>();
try
{
raw = Encryption.AES.Decrypt(
File.ReadAllBytes(FI.FullName),
OldPassword
);
}
catch (Exception e)
{
Console.WriteLine("Failed to decrypt file: '{0}'\nError: {1}", FI.FullName, e.ToString());
FI.Delete();
continue;
}
try
{
raw = Encryption.AES.Encrypt(raw,
NewPassword
);
}
catch (Exception e)
{
Console.WriteLine("Failed to encrypt file data: '{0}'\nError: {1}", FI.FullName, e.ToString());
continue;
}
try
{
File.WriteAllBytes(FI.FullName, raw);
}
catch (Exception e)
{
Console.WriteLine("Failed to write file data: '{0}'\nError: {1}", FI.FullName, e.ToString());
}
}
}
UpdateDir(GetStorageDirectory(StorageDirectory.ServerKeys));
UpdateDir(GetStorageDirectory(StorageDirectory.ChannelKeys));
for (int i = 0; i < Directories.Length; i++)
{
string full = Location;
string[] spl = Directories[i].Split('/');
if (!RawInfo.DontDelete && !CantDelete.Contains(i))
{
try
{
if (Directory.Exists(full + Directories[i])) Directory.Delete(full + Directories[i], true);
}
catch
{
// ignored
}
}
foreach (string d in spl)
{
full += d + "/";
if (!Directory.Exists(full)) Directory.CreateDirectory(full);
}
}
SetResourceBytes(StorageDirectory.StorageInfo, "lpk", OldPassword);
return NewPassword;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public byte[] GenerateStorage()
{
byte[] NewPassword = new byte[100];
byte[] OldPassword = new byte[100];
using (RandomNumberGenerator provider = RandomNumberGenerator.Create())
{
provider.GetBytes(OldPassword);
}
using (RandomNumberGenerator provider = RandomNumberGenerator.Create())
{
provider.GetBytes(NewPassword);
}
for (int i = 0; i < Directories.Length; i++)
{
string full = Location;
string[] spl = Directories[i].Split('/');
if (!RawInfo.DontDelete && !CantDelete.Contains(i))
{
try
{
if (Directory.Exists(full + Directories[i])) Directory.Delete(full + Directories[i], true);
}
catch
{
// ignored
}
}
foreach (string d in spl)
{
full += d + "/";
if (!Directory.Exists(full)) Directory.CreateDirectory(full);
}
}
SetResourceBytes(StorageDirectory.StorageInfo, "lpk", OldPassword);
return NewPassword;
}
public long StorageID { get; internal set; }
public string Location { get; internal set; }
public string GetStorageDirectory(StorageDirectory Directory)
{
return Location + Directories[(byte)Directory] + "/";
}
public string GetResourceDirectory(StorageDirectory Directory, string Resourse)
{
return Location + Directories[(byte)Directory] + "/" + Resourse;
}
public string GetResourceKey(StorageDirectory Directory, string Resource, string Key)
{
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Key));
}
public string GetResourceKeyRaw(StorageDirectory Directory, string Resource, byte[] Key)
{
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Key));
}
public LocalKeyInfo GetResourceKey(StorageDirectory Directory, string Resource, byte[] Key)
{
string str =
Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource),
Key));
string b = str.Split(':')[0];
str = str.Remove(0, b.Length + 1);
return new()
{
Key = str,
EncryptionType = (EncryptionType)short.Parse(b)
};
}
public void SetResourceKey(StorageDirectory Directory, string Resource, LocalKeyInfo Info, byte[] Key)
{
SetResourceKey(Directory, Resource, Key, $"{(int)Info.EncryptionType}:{Info.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), Key));
}
public void SetResourceKey(StorageDirectory Directory, string Resource, byte[] Key, byte[] value)
{
File.WriteAllBytes(GetStorageDirectory(Directory) + Resource, Encryption.AES.Encrypt(value, Key));
}
public byte[] GetResourceBytes(StorageDirectory Directory, string Resource)
{
return File.ReadAllBytes(Location + Directories[(byte)Directory] + "/" + Resource);
}
public Stream GetResourceStream(StorageDirectory Directory, string Resource)
{
byte[] buffer = new byte[16 * 1024];
MemoryStream ms = new();
using (FileStream r = File.OpenRead(Location + Directories[(byte)Directory] + "/" + Resource))
{
int readBytes;
while ((readBytes = r.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, readBytes);
}
}
ms.Position = 0;
return ms;
}
public Stream GetResourceStream(string dir)
{
byte[] buffer = new byte[16 * 1024];
MemoryStream ms = new();
using (FileStream r = File.OpenRead(dir))
{
int readBytes;
while ((readBytes = r.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, readBytes);
}
}
ms.Position = 0;
return ms;
}
public void SetResourceBytes(StorageDirectory Directory, string Resource, byte[] data)
{
File.WriteAllBytes(Location + Directories[(byte)Directory] + "/" + Resource, data);
}
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;
}
}
}