343 lines
11 KiB
C#
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;
|
|
}
|
|
}
|
|
} |