Luski.Net/Luski.net/PublicServer.Account.cs

292 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Authentication;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using JacobTechEncryption;
using JacobTechEncryption.Enums;
using Luski.net.Enums;
using Luski.net.JsonTypes;
using Luski.net.JsonTypes.WSS;
using Luski.net.Structures.Public;
using Luski.Shared.PublicServers.V1.ClientToServer.HTTP;
using Luski.Shared.PublicServers.V1.Enums;
using Luski.Shared.PublicServers.V1.ServerToClient.HTTP;
using WebSocketSharp;
using DataType = Luski.Shared.PublicServers.V1.Enums.DataType;
namespace Luski.net;
public partial class PublicServer
{
public async Task<bool> Login(string Username, string Password, CancellationToken CancellationToken)
{
return await All(Username, CancellationToken, Password);
}
public async Task<bool> CreateAccount(string Username, string Password, string DisplayName, string PFP, CancellationToken CancellationToken)
{
return await All(Username, CancellationToken, Password, DisplayName, PFP);
}
internal async Task<bool> LoginViaToken(string t)
{
Console.WriteLine("Starting Auto Login:");
bool b = await All(t, CancellationToken.None);
Console.WriteLine($"Auto Login {(b ? "Successful" : "Failed")}");
return b;
}
private async Task<bool> All(string Username, CancellationToken CancellationToken, string? Password = null, string? Displayname = null, string? pfp = null)
{
DateTime dt = DateTime.UtcNow;
Console.WriteLine("Encryption: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
if (!EncryptionHandler.Generating)
{
EncryptionHandler.GenerateKeys();
}
while (!EncryptionHandler.Generated) { Thread.Sleep(200); }
Console.WriteLine("Encryption 2: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
List<Tuple<string ,string, Exception>> FailedSystems = new();
login = true;
LoginSTC json;
List<KeyValuePair<string, string?>> heads = new()
{
new("key", EncryptionHandler.MyPublicKey),
new((Password is null ? "token" : "username"), Convert.ToBase64String(Encryption.RSA.Encrypt(Username, EncryptionHandler.ServerPublicKey, EncoderType.UTF16)))
};
if (Password is not null)
{
heads.Add(new("password", EncryptionHandler.RemotePasswordEncrypt(Encryption.Generic.Encoders[(int)EncoderType.UTF16].GetBytes(Password))));
}
if (File.Exists("LastPassVer.txt") && int.TryParse(File.ReadAllText("LastPassVer.txt"), out int lpv) && lpv < EncryptionHandler.PasswordVersion && lpv >= 0)
{
heads.Add(new("old_password", EncryptionHandler.RemotePasswordEncrypt(Encoding.Unicode.GetBytes(Password), lpv)));
heads.Add(new("old_version", lpv.ToString()));
}
if (pfp is not null)
{
heads.Add(new("displayname", Displayname));
json = await SendServer(
"SocketAccount",
pfp,
LoginSTCContext.Default.LoginSTC,
CancellationToken,
heads.ToArray());
}
else
{
json = await GetFromServer(
(Password is null ? "SocketAccount/AccessToken": "SocketAccount"),
LoginSTCContext.Default.LoginSTC,
CancellationToken,
heads.ToArray());
}
Console.WriteLine("Account Result: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
if (json.Error is not null)
{
Console.WriteLine(json.ErrorMessage);
return false;
throw new Exception($"Luski appears to be down at the current moment: {json.ErrorMessage}");
}
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)
{
ServerOut = new WebSocket(wssurl);
ServerOut.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12;
ServerOut.OnMessage += DataFromServer;
ServerOut.WaitTime = new TimeSpan(0, 0, 5);
ServerOut.EmitOnPing = true;
ServerOut.OnError += ServerOut_OnError;
ServerOut.Connect();
Console.WriteLine("WSS Connection: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
SendServer(DataType.Token, new WSSLogin() { Token = json.Token! });
while (Token is null && Error is null)
{
Thread.Sleep(200);
}
if (Error is not null)
{
throw new Exception(Error);
}
Console.WriteLine("WSS Login: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
if (Token is null) throw new Exception("Server did not send a token");
CanRequest = true;
long id = long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(
Token.Split('.')[0]
)));
User = await GetUser<SocketAppUser>(id, CancellationToken);
User.Username = Username;
Console.WriteLine("Get our info: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
#region Extra Systems
Task.Run(async () => {
#region Data Storage
try
{
StorageInfoSTC data;
if (Storage.StorageID == 0)
{
EncryptionHandler.Hash = Storage.GenerateStorage();
data = await SendServer("OfflineData/Info",
new StorageInfoCTS()
{
Password = Convert.ToBase64String(Encryption.AES.Encrypt(EncryptionHandler.Hash, Storage.GetResourceBytes(StorageDirectory.StorageInfo, "lpk")))
},
StorageInfoCTSContext.Default.StorageInfoCTS,
StorageInfoSTCContext.Default.StorageInfoSTC, CancellationToken,
new KeyValuePair<string, string?>("storage_id", Storage.StorageID.ToString()));
Storage.setid(data.ID);
}
else
{
data = await GetFromServer("OfflineData/Info", StorageInfoSTCContext.Default.StorageInfoSTC, CancellationToken, new KeyValuePair<string, string?>("storage_id", Storage.StorageID.ToString()));
}
Console.WriteLine("Offline Data Info: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
if (data.Update)
{
EncryptionHandler.Hash = Storage.UpdateStorage(Convert.FromBase64String(data.Password));
_ = await SendServerPatch("OfflineData/Info",
new StorageInfoCTS()
{
Password = Convert.ToBase64String(Encryption.AES.Encrypt(EncryptionHandler.Hash, Storage.GetResourceBytes(StorageDirectory.StorageInfo, "lpk")))
},
StorageInfoCTSContext.Default.StorageInfoCTS,
StorageInfoSTCContext.Default.StorageInfoSTC, CancellationToken,
new KeyValuePair<string, string?>("storage_id", Storage.StorageID.ToString()));
Console.WriteLine("Data Update: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
}
}
catch (Exception e)
{
FailedSystems.Add(new("Data Storage", e.Message, e));
}
#endregion
#region Key Generation
try
{
try
{
_ = EncryptionHandler.GetKey(0);
}
catch (Exception e)
{
EncryptionHandler.SetKey(0, new()
{
EncryptionType = EncryptionType.None,
Key = string.Empty
});
Console.WriteLine("Key 0: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
}
}
catch (Exception e)
{
FailedSystems.Add(new("Key Generation", "Key 0 Failed to generate", e));
}
#endregion
#region Auto Status
try
{
_ = await UpdateStatus(UserStatus.Online, CancellationToken);
Console.WriteLine("Status: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
}
catch (Exception e)
{
FailedSystems.Add(new("Auto Status", "Failed to set status on the server", e));
}
#endregion
#region GetRoles
try
{
_ = await GetRoles();
}
catch (Exception e)
{
FailedSystems.Add(new("Get Roles", "Failed to get roles on the server", e));
}
#endregion
#region Local Storage Cleanup
try
{
KeyValuePair<string, string?> stor = new("storage_id", Storage.StorageID.ToString());
OfflineDataBlobSTC offlinedata = await GetFromServer("OfflineData", OfflineDataBlobSTCContext.Default.OfflineDataBlobSTC, CancellationToken, stor);
Console.WriteLine("Offline Data: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
if (offlinedata is not null && offlinedata.Error is null && offlinedata.Data is not null && offlinedata.Data.Length > 0)
{
string pkey = Storage.GetResourceKeyRaw(
StorageDirectory.ServerKeys,
"pkey",
EncryptionHandler.Hash
);
foreach (string keyexx in offlinedata.Data)
{
string keyex = Encoding.UTF8.GetString(Convert.FromBase64String(keyexx));
KeyExchange? okd = JsonSerializer.Deserialize<KeyExchange>(keyex);
if (okd is not null && !string.IsNullOrEmpty(okd.key))
{
Storage.SetResourceKey(
StorageDirectory.ServerKeys,
okd.id.ToString(),
EncryptionHandler.Hash,
Encoding.Unicode.GetString(
Encryption.RSA.Decrypt(
Convert.FromBase64String(okd.key),
pkey
)
)
);
}
}
}
System.IO.File.WriteAllText("LastPassVer.txt", EncryptionHandler.PasswordVersion.ToString());
Storage.SetResourceKey(StorageDirectory.ServerKeys, "pkey", EncryptionHandler.Hash, EncryptionHandler.OfflinePrivateKey);
KeyPostCTS OfflineKeySetRequest = new()
{
Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(EncryptionHandler.OfflinePublicKey)),
EncryptionType = EncryptionType.RSA
};
_ = await SendServer("Keys/SetOfflineKey",
OfflineKeySetRequest,
KeyPostCTSContext.Default.KeyPostCTS,
STCContext.Default.STC,
CancellationToken.None,
stor);
Console.WriteLine("Offline Key: " + DateTime.UtcNow.Subtract(dt).ToString("g"));
EncryptionHandler.OfflinePublicKey = null!;
EncryptionHandler.OfflinePrivateKey = null!;
}
catch (Exception e)
{
FailedSystems.Add(new("Local Storage Cleanup", "Failed to clean the local storage", e));
}
#endregion
if (FailedSystems.Count > 0)
{
Console.WriteLine("Some systems have failed:");
foreach (Tuple<string, string, Exception> System in FailedSystems)
{
Console.WriteLine($"\t{System.Item1}:\n\t\tMessage: {System.Item2}\n\t\tError Details: {System.Item3}");
}
} });
#endregion
return true;
}
else throw new Exception(json?.ErrorMessage);
return true;
}
}