blizzless-diiis/src/DiIiS-NA/BGS-Server/AccountsSystem/AccountManager.cs

333 lines
9.4 KiB
C#

//Blizzless Project 2022
using DiIiS_NA.Core.Extensions;
using DiIiS_NA.Core.Logging;
using DiIiS_NA.Core.Storage;
using DiIiS_NA.Core.Storage.AccountDataBase.Entities;
using DiIiS_NA.LoginServer.Crypthography;
using DiIiS_NA.LoginServer.Toons;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Spectre.Console;
using System.Text.RegularExpressions;
namespace DiIiS_NA.LoginServer.AccountsSystem
{
public static class AccountManager
{
private static readonly Logger Logger = LogManager.CreateLogger("DataBaseSystem");
public static int TotalAccounts => DBSessions.SessionQuery<DBAccount>().Count();
public static readonly ConcurrentDictionary<ulong, Account> LoadedAccounts = new();
public static void PreLoadAccounts()
{
Logger.Info("Loading accounts...");
List<DBAccount> all_accounts = DBSessions.SessionQuery<DBAccount>();
foreach (var account in all_accounts)
{
LoadedAccounts.TryAdd(account.Id, new Account(account));
}
}
#region AccountGetter
public static Account CreateAccount(string email, string password, string battleTag, Account.UserLevels userLevel = Account.UserLevels.User)
{
if (password.Length > 16) password = password.Substring(0, 16); // make sure the password does not exceed 16 chars.
var hashCode = GetRandomHashCodeForBattleTag();
var salt = SRP6a.GetRandomBytes(32);
var passwordVerifier = SRP6a.CalculatePasswordVerifierForAccount(email, password, salt);
var saltedticket = password + " asa " + email;
var newDBAccount = new DBAccount
{
Email = email,
Banned = false,
Salt = salt,
PasswordVerifier = passwordVerifier,
SaltedTicket = saltedticket,
BattleTagName = battleTag,
UserLevel = userLevel,
HashCode = hashCode
};
DBSessions.SessionSave(newDBAccount);
//GenerateReferralCode(email);
Logger.Warn("Created account {0}", email);
return GetAccountByEmail(email);
}
public static bool BindDiscordAccount(string email, ulong discordId, string discordTag)
{
try
{
if (DBSessions.SessionQueryWhere<DBAccount>(dba => dba.DiscordId == discordId).Any())
return false;
var account = GetAccountByEmail(email);
account.DBAccount.DiscordTag = discordTag;
account.DBAccount.DiscordId = discordId;
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch (Exception e)
{
Logger.DebugException(e, "BindDiscordAccount() exception: ");
return false;
}
}
public static Account GetAccountByDiscordId(ulong discordId)
{
List<DBAccount> dbAcc = DBSessions.SessionQueryWhere<DBAccount>(dba => dba.DiscordId == discordId).ToList();
if (dbAcc.Count() == 0)
{
Logger.Warn("GetAccountByDiscordId {0}: DBAccount is null!", discordId);
return null;
}
return GetAccountByDBAccount(dbAcc.First());
}
public static bool GenerateReferralCode(string email)
{
try
{
var account = GetAccountByEmail(email);
account.DBAccount.ReferralCode = ((int)(account.DBAccount.Id * 17) + Core.Helpers.Math.FastRandom.Instance.Next(16));
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch
{
return false;
}
}
public static bool SetInvitee(string email, int invitee_code)
{
try
{
var invitee_account = DBSessions.SessionQuerySingle<DBAccount>(dba => dba.ReferralCode == invitee_code);
var account = GetAccountByEmail(email);
account.DBAccount.InviteeAccount = invitee_account;
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch
{
return false;
}
}
public static Account GetAccountByEmail(string email)
{
if (LoadedAccounts.Any(a => a.Value.Email.ToLower() == email.ToLower()))
return LoadedAccounts[LoadedAccounts.Single(a => a.Value.Email.ToLower() == email.ToLower()).Key];
else
{
List<DBAccount> dbAcc = DBSessions.SessionQueryWhere<DBAccount>(dba => dba.Email == email);
if (dbAcc.Count == 0)
{
Logger.Warn($"$[olive]$GetAccountByEmail(\"{email}\")$[/]$: DBAccount is null!");
return null;
}
if (dbAcc.First() == null)
{
Logger.Warn($"$[olive]$GetAccountByEmail(\"{email}\")$[/]$: DBAccount id is not null!");
return null;
}
else
Logger.MethodTrace($"$[olive]$GetAccountByEmail(\"{email}\")$[/]$: id - {dbAcc.First().Id}");
return GetAccountByDBAccount(dbAcc.First());
}
}
public static Account GetAccountByBattletag(string battletag)
{
string[] tagparts = battletag.Split(new[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
int taghash = Convert.ToInt32(tagparts[1], 10);
// remove everything inside the brackets and empty spaces in tagparts[0] using regex
tagparts[0] = Regex.Replace(tagparts[0], @"\s*?{[^}]+}\s*?", string.Empty).Trim();
tagparts[0] = Regex.Replace(tagparts[0], @"\s*?", string.Empty).Trim();
// if (tagparts[0].StartsWith(" {icon"))
// tagparts[0] = tagparts[0].Substring(13);
// //Logger.Debug("trying GetAccountByBattletag {0}", battletag);
// if (tagparts[0].StartsWith("{c_legendary"))
// {
// tagparts[0] = tagparts[0].Substring(13);
// tagparts[0] = tagparts[0].Split('{')[0];
// }
List<DBAccount> dbAcc = DBSessions.SessionQueryWhere<DBAccount>(dba => dba.BattleTagName == tagparts[0] && dba.HashCode == taghash);
if (dbAcc.Count == 0)
{
Logger.Warn($"$[olive]$GetAccountByBattleTag(\"{battletag})$[/]$ DBAccount is null!");
return null;
}
//else
//Logger.Debug("GetAccountByBattletag \"{0}\"", battletag);
return GetAccountByDBAccount(dbAcc.First());
}
public static Account GetAccountByName(string btname) //pretty bad to use it
{
List<DBAccount> dbAcc = DBSessions.SessionQueryWhere<DBAccount>(dba => dba.BattleTagName == btname);
if (dbAcc.Count == 0)
{
Logger.Warn("$[olive]$GetAccountByName(\"{0}\")$[/]$: DBAccount is null!", btname);
return null;
}
return GetAccountByDBAccount(dbAcc.First());
}
public static Account GetAccountByPersistentID(ulong persistentId)
{
if (LoadedAccounts.ContainsKey(persistentId))
return LoadedAccounts[persistentId];
else
{
return GetAccountByDBAccount(DBSessions.SessionGet<DBAccount>(persistentId));
}
}
public static Account GetAccountByDBAccount(DBAccount dbAccount)
{
if (dbAccount == null)
return null;
if (LoadedAccounts.ContainsKey(dbAccount.Id))
{
LoadedAccounts[dbAccount.Id].DBAccount = dbAccount;
return LoadedAccounts[dbAccount.Id];
}
else
{
var account = new Account(dbAccount);
LoadedAccounts.TryAdd(dbAccount.Id, account);
return account;
}
}
#endregion
#region Managing Functions, also extending Account
public static bool UpdatePassword(this Account account, string newPassword)
{
try
{
account.PasswordVerifier = SRP6a.CalculatePasswordVerifierForAccount(account.Email, newPassword, account.Salt);
return true;
}
catch (Exception e)
{
Logger.ErrorException(e, "UpdatePassword()");
return false;
}
}
public static bool UpdateBattleTag(this Account account, string newName)
{
Logger.Info("Renaming account \"{0}\"", account.Email);
try
{
if (account.DBAccount.HasRename == false) return false;
int newHash = GetRandomHashCodeForBattleTag();
Logger.RenameAccount("{0}#{1} -> {2}#{3}", account.DBAccount.BattleTagName, account.DBAccount.HashCode, newName, newHash);
account.DBAccount.BattleTagName = newName;
account.DBAccount.HashCode = newHash;
account.DBAccount.HasRename = false;
account.DBAccount.RenameCooldown = DateTime.Now.ToExtendedEpoch() + 2592000000000;
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch (Exception e)
{
Logger.ErrorException(e, "UpdatePassword()");
return false;
}
}
public static bool UnlockRename(this Account account)
{
Logger.Info("Rename unlock for account \"{0}\"", account.Email);
try
{
account.DBAccount.HasRename = true;
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch (Exception e)
{
Logger.ErrorException(e, "UnlockRename()");
return false;
}
}
public static Account GetAccountBySaltTicket(string ticket)
{
if (DBSessions.SessionQueryWhere<DBAccount>(dba => dba.SaltedTicket == ticket).Any())
return LoadedAccounts[LoadedAccounts.Single(a => a.Value.SaltedTicket == ticket).Key];
return null;
}
public static bool AddMoney(this Account account, int money)
{
try
{
if (money <= 0) return false;
account.DBAccount.Money += (ulong)money;
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch (Exception e)
{
Logger.ErrorException(e, "AddMoney()");
return false;
}
}
public static bool SubMoney(this Account account, int money)
{
try
{
if (money <= 0) return false;
if (account.DBAccount.Money < (ulong)money) return false;
account.DBAccount.Money -= (ulong)money;
DBSessions.SessionUpdate(account.DBAccount);
return true;
}
catch (Exception e)
{
Logger.ErrorException(e, "SubMoney()");
return false;
}
}
public static void UpdateUserLevel(this Account account, Account.UserLevels userLevel)
{
try
{
account.UserLevel = userLevel;
}
catch (Exception e)
{
Logger.ErrorException(e, "UpdateUserLevel()");
}
}
#endregion
private static int GetRandomHashCodeForBattleTag()
{
var rnd = new Random();
return rnd.Next(1, 10000);
}
}
}