Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Accounts;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public sealed class AccountManager : Singleton<AccountManager>
|
||||
{
|
||||
const int MaxAccountLength = 16;
|
||||
const int MaxEmailLength = 64;
|
||||
|
||||
AccountManager() { }
|
||||
|
||||
public AccountOpResult CreateAccount(string username, string password, string email = "", uint bnetAccountId = 0, byte bnetIndex = 0)
|
||||
{
|
||||
if (username.Length > MaxAccountLength)
|
||||
return AccountOpResult.NameTooLong; // username's too long
|
||||
|
||||
if (password.Length > MaxAccountLength)
|
||||
return AccountOpResult.PassTooLong; // password's too long
|
||||
|
||||
if (GetId(username) != 0)
|
||||
return AccountOpResult.NameAlreadyExist; // username does already exist
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_ACCOUNT);
|
||||
stmt.AddValue(0, username);
|
||||
stmt.AddValue(1, CalculateShaPassHash(username, password));
|
||||
stmt.AddValue(2, email);
|
||||
stmt.AddValue(3, email);
|
||||
if (bnetAccountId != 0 && bnetIndex != 0)
|
||||
{
|
||||
stmt.AddValue(4, bnetAccountId);
|
||||
stmt.AddValue(5, bnetIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt.AddValue(4, null);
|
||||
stmt.AddValue(5, null);
|
||||
}
|
||||
DB.Login.Execute(stmt); // Enforce saving, otherwise AddGroup can fail
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_REALM_CHARACTERS_INIT);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok; // everything's fine
|
||||
}
|
||||
|
||||
public AccountOpResult DeleteAccount(uint accountId)
|
||||
{
|
||||
// Check if accounts exists
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
// Obtain accounts characters
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARS_BY_ACCOUNT_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ObjectGuid guid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
|
||||
// Kick if player is online
|
||||
Player p = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (p)
|
||||
{
|
||||
WorldSession s = p.GetSession();
|
||||
s.KickPlayer(); // mark session to remove at next session list update
|
||||
s.LogoutPlayer(false); // logout player without waiting next session list update
|
||||
}
|
||||
|
||||
Player.DeleteFromDB(guid, accountId, false); // no need to update realm characters
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
// table realm specific but common for all characters of account for realm
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_TUTORIALS);
|
||||
stmt.AddValue(0, accountId);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ACCOUNT_DATA);
|
||||
stmt.AddValue(0, accountId);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHARACTER_BAN);
|
||||
stmt.AddValue(0, accountId);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_ACCESS);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_REALM_CHARACTERS);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_BANNED);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_MUTED);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Login.CommitTransaction(trans);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangeUsername(uint accountId, string newUsername, string newPassword)
|
||||
{
|
||||
// Check if accounts exists
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (newUsername.Length > MaxAccountLength)
|
||||
return AccountOpResult.NameTooLong;
|
||||
|
||||
if (newPassword.Length > MaxAccountLength)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_USERNAME);
|
||||
stmt.AddValue(0, newUsername);
|
||||
stmt.AddValue(1, CalculateShaPassHash(newUsername, newPassword));
|
||||
stmt.AddValue(2, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangePassword(uint accountId, string newPassword)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist; // account doesn't exist
|
||||
|
||||
if (newPassword.Length > MaxAccountLength)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_PASSWORD);
|
||||
stmt.AddValue(0, CalculateShaPassHash(username, newPassword));
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_VS);
|
||||
stmt.AddValue(0, "");
|
||||
stmt.AddValue(1, "");
|
||||
stmt.AddValue(2, username);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangeEmail(uint accountId, string newEmail)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist; // account doesn't exist
|
||||
|
||||
if (newEmail.Length > MaxEmailLength)
|
||||
return AccountOpResult.EmailTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_EMAIL);
|
||||
stmt.AddValue(0, newEmail);
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangeRegEmail(uint accountId, string newEmail)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist; // account doesn't exist
|
||||
|
||||
if (newEmail.Length > MaxEmailLength)
|
||||
return AccountOpResult.EmailTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_REG_EMAIL);
|
||||
stmt.AddValue(0, newEmail);
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public uint GetId(string username)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_ACCOUNT_ID_BY_USERNAME);
|
||||
stmt.AddValue(0, username);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return !result.IsEmpty() ? result.Read<uint>(0) : 0;
|
||||
}
|
||||
|
||||
public AccountTypes GetSecurity(uint accountId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_ACCOUNT_ACCESS_GMLEVEL);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return !result.IsEmpty() ? (AccountTypes)result.Read<byte>(0) : AccountTypes.Player;
|
||||
}
|
||||
|
||||
public AccountTypes GetSecurity(uint accountId, int realmId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_GMLEVEL_BY_REALMID);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, realmId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return !result.IsEmpty() ? (AccountTypes)result.Read<uint>(0) : AccountTypes.Player;
|
||||
}
|
||||
|
||||
public bool GetName(uint accountId, out string name)
|
||||
{
|
||||
name = "";
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_USERNAME_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
name = result.Read<string>(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetEmail(uint accountId, out string email)
|
||||
{
|
||||
email = "";
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_EMAIL_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
email = result.Read<string>(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckPassword(uint accountId, string password)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_CHECK_PASSWORD);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, CalculateShaPassHash(username, password));
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return result.IsEmpty() ? false : true;
|
||||
}
|
||||
|
||||
public bool CheckEmail(uint accountId, string newEmail)
|
||||
{
|
||||
string oldEmail;
|
||||
|
||||
// We simply return false for a non-existing email
|
||||
if (!GetEmail(accountId, out oldEmail))
|
||||
return false;
|
||||
|
||||
if (oldEmail == newEmail)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetCharactersCount(uint accountId)
|
||||
{
|
||||
// check character count
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_SUM_CHARS);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
return result.IsEmpty() ? 0 : (uint)result.Read<ulong>(0);
|
||||
}
|
||||
|
||||
string CalculateShaPassHash(string name, string password)
|
||||
{
|
||||
SHA1 sha = SHA1.Create();
|
||||
return sha.ComputeHash(Encoding.UTF8.GetBytes(name + ":" + password)).ToHexString();
|
||||
}
|
||||
|
||||
public bool IsPlayerAccount(AccountTypes gmlevel)
|
||||
{
|
||||
return gmlevel == AccountTypes.Player;
|
||||
}
|
||||
|
||||
public bool IsAdminAccount(AccountTypes gmlevel)
|
||||
{
|
||||
return gmlevel >= AccountTypes.Administrator && gmlevel <= AccountTypes.Console;
|
||||
}
|
||||
|
||||
public bool IsConsoleAccount(AccountTypes gmlevel)
|
||||
{
|
||||
return gmlevel == AccountTypes.Console;
|
||||
}
|
||||
|
||||
public void LoadRBAC()
|
||||
{
|
||||
ClearRBAC();
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC");
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
uint count1 = 0;
|
||||
uint count2 = 0;
|
||||
uint count3 = 0;
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading permissions");
|
||||
SQLResult result = DB.Login.Query("SELECT id, name FROM rbac_permissions");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 account permission definitions. DB table `rbac_permissions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
uint id = result.Read<uint>(0);
|
||||
_permissions[id] = new RBACPermission(id, result.Read<string>(1));
|
||||
++count1;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading linked permissions");
|
||||
result = DB.Login.Query("SELECT id, linkedId FROM rbac_linked_permissions ORDER BY id ASC");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 linked permissions. DB table `rbac_linked_permissions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint permissionId = 0;
|
||||
RBACPermission permission = null;
|
||||
|
||||
do
|
||||
{
|
||||
uint newId = result.Read<uint>(0);
|
||||
if (permissionId != newId)
|
||||
{
|
||||
permissionId = newId;
|
||||
permission = _permissions[newId];
|
||||
}
|
||||
|
||||
uint linkedPermissionId = result.Read<uint>(1);
|
||||
if (linkedPermissionId == permissionId)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RBAC Permission {0} has itself as linked permission. Ignored", permissionId);
|
||||
continue;
|
||||
}
|
||||
permission.AddLinkedPermission(linkedPermissionId);
|
||||
++count2;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading default permissions");
|
||||
result = DB.Login.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint secId = 255;
|
||||
do
|
||||
{
|
||||
uint newId = result.Read<uint>(0);
|
||||
if (secId != newId)
|
||||
secId = newId;
|
||||
|
||||
_defaultPermissions.Add((byte)secId, result.Read<uint>(1));
|
||||
++count3;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} permission definitions, {1} linked permissions and {2} default permissions in {3} ms", count1, count2, count3, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void UpdateAccountAccess(RBACData rbac, uint accountId, byte securityLevel, int realmId)
|
||||
{
|
||||
if (rbac != null && securityLevel != rbac.GetSecurityLevel())
|
||||
rbac.SetSecurityLevel(securityLevel);
|
||||
|
||||
PreparedStatement stmt;
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
// Delete old security level from DB
|
||||
if (realmId == -1)
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_ACCESS);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_ACCESS_BY_REALM);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, realmId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
// Add new security level
|
||||
if (securityLevel != 0)
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_ACCOUNT_ACCESS);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, securityLevel);
|
||||
stmt.AddValue(2, realmId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
DB.Login.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public RBACPermission GetRBACPermission(uint permissionId)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:GetRBACPermission: {0}", permissionId);
|
||||
return _permissions.LookupByKey(permissionId);
|
||||
}
|
||||
|
||||
public bool HasPermission(uint accountId, RBACPermissions permissionId, uint realmId)
|
||||
{
|
||||
if (accountId == 0)
|
||||
{
|
||||
Log.outError(LogFilter.Rbac, "AccountMgr:HasPermission: Wrong accountId 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACData rbac = new RBACData(accountId, "", (int)realmId);
|
||||
rbac.LoadFromDB();
|
||||
bool hasPermission = rbac.HasPermission(permissionId);
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:HasPermission [AccountId: {0}, PermissionId: {1}, realmId: {2}]: {3}",
|
||||
accountId, permissionId, realmId, hasPermission);
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
void ClearRBAC()
|
||||
{
|
||||
_permissions.Clear();
|
||||
_defaultPermissions.Clear();
|
||||
}
|
||||
|
||||
public List<uint> GetRBACDefaultPermissions(byte secLevel)
|
||||
{
|
||||
return _defaultPermissions[secLevel];
|
||||
}
|
||||
|
||||
public Dictionary<uint, RBACPermission> GetRBACPermissionList() { return _permissions; }
|
||||
|
||||
Dictionary<uint, RBACPermission> _permissions = new Dictionary<uint, RBACPermission>();
|
||||
MultiMap<byte, uint> _defaultPermissions = new MultiMap<byte, uint>();
|
||||
}
|
||||
|
||||
public enum AccountOpResult
|
||||
{
|
||||
Ok,
|
||||
NameTooLong,
|
||||
PassTooLong,
|
||||
EmailTooLong,
|
||||
NameAlreadyExist,
|
||||
NameNotExist,
|
||||
DBInternalError,
|
||||
BadLink
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Database;
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public sealed class BNetAccountManager : Singleton<BNetAccountManager>
|
||||
{
|
||||
BNetAccountManager() { }
|
||||
|
||||
public AccountOpResult CreateBattlenetAccount(string email, string password, bool withGameAccount, out string gameAccountName)
|
||||
{
|
||||
gameAccountName = "";
|
||||
|
||||
if (email.Length > 320)
|
||||
return AccountOpResult.NameTooLong;
|
||||
|
||||
if (password.Length > 16)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
if (GetId(email) != 0)
|
||||
return AccountOpResult.NameAlreadyExist;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_ACCOUNT);
|
||||
stmt.AddValue(0, email);
|
||||
stmt.AddValue(1, CalculateShaPassHash(email, password));
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
uint newAccountId = GetId(email);
|
||||
Contract.Assert(newAccountId != 0);
|
||||
|
||||
if (withGameAccount)
|
||||
{
|
||||
gameAccountName = newAccountId + "#1";
|
||||
Global.AccountMgr.CreateAccount(gameAccountName, password, email, newAccountId, 1);
|
||||
}
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangePassword(uint accountId, string newPassword)
|
||||
{
|
||||
string username;
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (newPassword.Length > 16)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_PASSWORD);
|
||||
stmt.AddValue(0, CalculateShaPassHash(username, newPassword));
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public bool CheckPassword(uint accountId, string password)
|
||||
{
|
||||
string username;
|
||||
if (!GetName(accountId, out username))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_CHECK_PASSWORD);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, CalculateShaPassHash(username, password));
|
||||
|
||||
return !DB.Login.Query(stmt).IsEmpty();
|
||||
}
|
||||
|
||||
public AccountOpResult LinkWithGameAccount(string email, string gameAccountName)
|
||||
{
|
||||
uint bnetAccountId = GetId(email);
|
||||
if (bnetAccountId == 0)
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
uint gameAccountId = Global.AccountMgr.GetId(gameAccountName);
|
||||
if (gameAccountId == 0)
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (GetIdByGameAccount(gameAccountId) != 0)
|
||||
return AccountOpResult.BadLink;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LINK);
|
||||
stmt.AddValue(0, bnetAccountId);
|
||||
stmt.AddValue(1, GetMaxIndex(bnetAccountId) + 1);
|
||||
stmt.AddValue(2, gameAccountId);
|
||||
DB.Login.Execute(stmt);
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult UnlinkGameAccount(string gameAccountName)
|
||||
{
|
||||
uint gameAccountId = Global.AccountMgr.GetId(gameAccountName);
|
||||
if (gameAccountId == 0)
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (GetIdByGameAccount(gameAccountId) == 0)
|
||||
return AccountOpResult.BadLink;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LINK);
|
||||
stmt.AddValue(0, null);
|
||||
stmt.AddValue(1, null);
|
||||
stmt.AddValue(2, gameAccountId);
|
||||
DB.Login.Execute(stmt);
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public uint GetId(string username)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_ID_BY_EMAIL);
|
||||
stmt.AddValue(0, username);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
return result.Read<uint>(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool GetName(uint accountId, out string name)
|
||||
{
|
||||
name = "";
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_EMAIL_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
name = result.Read<string>(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetIdByGameAccount(uint gameAccountId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT);
|
||||
stmt.AddValue(0, gameAccountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
return result.Read<uint>(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public byte GetMaxIndex(uint accountId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_MAX_ACCOUNT_INDEX);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
return result.Read<byte>(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string CalculateShaPassHash(string name, string password)
|
||||
{
|
||||
SHA256 sha256 = SHA256.Create();
|
||||
var i = sha256.ComputeHash(Encoding.UTF8.GetBytes(name));
|
||||
return sha256.ComputeHash(Encoding.UTF8.GetBytes(i.ToHexString() + ":" + password)).ToHexString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Accounts
|
||||
{
|
||||
public class RBACData
|
||||
{
|
||||
public RBACData(uint id, string name, int realmId, byte secLevel = 255)
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
_realmId = realmId;
|
||||
_secLevel = secLevel;
|
||||
}
|
||||
|
||||
public RBACCommandResult GrantPermission(uint permissionId, int realmId = 0)
|
||||
{
|
||||
// Check if permission Id exists
|
||||
RBACPermission perm = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (perm == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission does not exists",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.IdDoesNotExists;
|
||||
}
|
||||
|
||||
// Check if already added in denied list
|
||||
if (HasDeniedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission in deny list",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.InDeniedList;
|
||||
}
|
||||
|
||||
// Already added?
|
||||
if (HasGrantedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission already granted",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.CantAddAlreadyAdded;
|
||||
}
|
||||
|
||||
AddGrantedPermission(permissionId);
|
||||
|
||||
// Do not save to db when loading data from DB (realmId = 0)
|
||||
if (realmId != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok and DB updated",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
SavePermission(permissionId, true, realmId);
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
|
||||
return RBACCommandResult.OK;
|
||||
}
|
||||
|
||||
public RBACCommandResult DenyPermission(uint permissionId, int realmId = 0)
|
||||
{
|
||||
// Check if permission Id exists
|
||||
RBACPermission perm = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (perm == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission does not exists",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.IdDoesNotExists;
|
||||
}
|
||||
|
||||
// Check if already added in granted list
|
||||
if (HasGrantedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission in grant list",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.InGrantedList;
|
||||
}
|
||||
|
||||
// Already added?
|
||||
if (HasDeniedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission already denied",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.CantAddAlreadyAdded;
|
||||
}
|
||||
|
||||
AddDeniedPermission(permissionId);
|
||||
|
||||
// Do not save to db when loading data from DB (realmId = 0)
|
||||
if (realmId != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok and DB updated",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
SavePermission(permissionId, false, realmId);
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
|
||||
return RBACCommandResult.OK;
|
||||
}
|
||||
|
||||
void SavePermission(uint permission, bool granted, int realmId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_RBAC_ACCOUNT_PERMISSION);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, permission);
|
||||
stmt.AddValue(2, granted);
|
||||
stmt.AddValue(3, realmId);
|
||||
DB.Login.Execute(stmt);
|
||||
}
|
||||
|
||||
public RBACCommandResult RevokePermission(uint permissionId, int realmId = 0)
|
||||
{
|
||||
// Check if it's present in any list
|
||||
if (!HasGrantedPermission(permissionId) && !HasDeniedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.RevokePermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Not granted or revoked",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.CantRevokeNotInList;
|
||||
}
|
||||
|
||||
RemoveGrantedPermission(permissionId);
|
||||
RemoveDeniedPermission(permissionId);
|
||||
|
||||
// Do not save to db when loading data from DB (realmId = 0)
|
||||
if (realmId != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.RevokePermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok and DB updated",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_RBAC_ACCOUNT_PERMISSION);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, permissionId);
|
||||
stmt.AddValue(2, realmId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.RevokePermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
|
||||
return RBACCommandResult.OK;
|
||||
}
|
||||
|
||||
public void LoadFromDB()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.LoadFromDB [Id: {0} Name: {1}]: Loading permissions", GetId(), GetName());
|
||||
// Load account permissions (granted and denied) that affect current realm
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_RBAC_ACCOUNT_PERMISSIONS);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, GetRealmId());
|
||||
|
||||
LoadFromDBCallback(DB.Login.Query(stmt));
|
||||
}
|
||||
|
||||
public QueryCallback LoadFromDBAsync()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.LoadFromDB [Id: {0} Name: {1}]: Loading permissions", GetId(), GetName());
|
||||
// Load account permissions (granted and denied) that affect current realm
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_RBAC_ACCOUNT_PERMISSIONS);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, GetRealmId());
|
||||
|
||||
return DB.Login.AsyncQuery(stmt);
|
||||
}
|
||||
|
||||
public void LoadFromDBCallback(SQLResult result)
|
||||
{
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
if (result.Read<bool>(1))
|
||||
GrantPermission(result.Read<uint>(0));
|
||||
else
|
||||
DenyPermission(result.Read<uint>(0));
|
||||
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
// Add default permissions
|
||||
List<uint> permissions = Global.AccountMgr.GetRBACDefaultPermissions(_secLevel);
|
||||
foreach (var id in permissions)
|
||||
GrantPermission(id);
|
||||
|
||||
// Force calculation of permissions
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
|
||||
void CalculateNewPermissions()
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.CalculateNewPermissions [Id: {0} Name: {1}]", GetId(), GetName());
|
||||
|
||||
// Get the list of granted permissions
|
||||
_globalPerms = GetGrantedPermissions();
|
||||
ExpandPermissions(_globalPerms);
|
||||
List<uint> revoked = GetDeniedPermissions();
|
||||
ExpandPermissions(revoked);
|
||||
RemovePermissions(_globalPerms, revoked);
|
||||
}
|
||||
|
||||
void AddPermissions(List<uint> permsFrom, List<uint> permsTo)
|
||||
{
|
||||
foreach (var id in permsFrom)
|
||||
permsTo.Add(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a list of permissions from another list
|
||||
/// </summary>
|
||||
/// <param name="permsFrom"></param>
|
||||
/// <param name="permsToRemove"></param>
|
||||
void RemovePermissions(List<uint> permsFrom, List<uint> permsToRemove)
|
||||
{
|
||||
foreach (var id in permsToRemove)
|
||||
permsFrom.Remove(id);
|
||||
}
|
||||
|
||||
void ExpandPermissions(List<uint> permissions)
|
||||
{
|
||||
List<uint> toCheck = new List<uint>(permissions);
|
||||
permissions.Clear();
|
||||
|
||||
while (!toCheck.Empty())
|
||||
{
|
||||
// remove the permission from original list
|
||||
uint permissionId = toCheck.FirstOrDefault();
|
||||
toCheck.RemoveAt(0);
|
||||
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (permission == null)
|
||||
continue;
|
||||
|
||||
// insert into the final list (expanded list)
|
||||
permissions.Add(permissionId);
|
||||
|
||||
// add all linked permissions (that are not already expanded) to the list of permissions to be checked
|
||||
List<uint> linkedPerms = permission.GetLinkedPermissions();
|
||||
foreach (var id in linkedPerms)
|
||||
if (!permissions.Contains(id))
|
||||
toCheck.Add(id);
|
||||
}
|
||||
|
||||
//Log.outDebug(LogFilter.General, "RBACData:ExpandPermissions: Expanded: {0}", GetDebugPermissionString(permissions));
|
||||
}
|
||||
|
||||
void ClearData()
|
||||
{
|
||||
_grantedPerms.Clear();
|
||||
_deniedPerms.Clear();
|
||||
_globalPerms.Clear();
|
||||
}
|
||||
|
||||
// Gets the Name of the Object
|
||||
public string GetName() { return _name; }
|
||||
// Gets the Id of the Object
|
||||
public uint GetId() { return _id; }
|
||||
|
||||
public bool HasPermission(RBACPermissions permission)
|
||||
{
|
||||
return _globalPerms.Contains((uint)permission);
|
||||
}
|
||||
|
||||
// Returns all the granted permissions (after computation)
|
||||
public List<uint> GetPermissions() { return _globalPerms; }
|
||||
// Returns all the granted permissions
|
||||
public List<uint> GetGrantedPermissions() { return _grantedPerms; }
|
||||
// Returns all the denied permissions
|
||||
public List<uint> GetDeniedPermissions() { return _deniedPerms; }
|
||||
|
||||
public void SetSecurityLevel(byte id)
|
||||
{
|
||||
_secLevel = id;
|
||||
LoadFromDB();
|
||||
}
|
||||
|
||||
public byte GetSecurityLevel() { return _secLevel; }
|
||||
int GetRealmId() { return _realmId; }
|
||||
|
||||
// Checks if a permission is granted
|
||||
bool HasGrantedPermission(uint permissionId)
|
||||
{
|
||||
return _grantedPerms.Contains(permissionId);
|
||||
}
|
||||
|
||||
// Checks if a permission is denied
|
||||
bool HasDeniedPermission(uint permissionId)
|
||||
{
|
||||
return _deniedPerms.Contains(permissionId);
|
||||
}
|
||||
|
||||
// Adds a new granted permission
|
||||
void AddGrantedPermission(uint permissionId)
|
||||
{
|
||||
_grantedPerms.Add(permissionId);
|
||||
}
|
||||
|
||||
// Removes a granted permission
|
||||
void RemoveGrantedPermission(uint permissionId)
|
||||
{
|
||||
_grantedPerms.Remove(permissionId);
|
||||
}
|
||||
|
||||
// Adds a new denied permission
|
||||
void AddDeniedPermission(uint permissionId)
|
||||
{
|
||||
_deniedPerms.Add(permissionId);
|
||||
}
|
||||
|
||||
// Removes a denied permission
|
||||
void RemoveDeniedPermission(uint permissionId)
|
||||
{
|
||||
_deniedPerms.Remove(permissionId);
|
||||
}
|
||||
|
||||
uint _id; // Account id
|
||||
string _name; // Account name
|
||||
int _realmId; // RealmId Affected
|
||||
byte _secLevel; // Account SecurityLevel
|
||||
List<uint> _grantedPerms = new List<uint>(); // Granted permissions
|
||||
List<uint> _deniedPerms = new List<uint>(); // Denied permissions
|
||||
List<uint> _globalPerms = new List<uint>(); // Calculated permissions
|
||||
}
|
||||
|
||||
public class RBACPermission
|
||||
{
|
||||
public RBACPermission(uint id = 0, string name = "")
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
// Gets the Name of the Object
|
||||
public string GetName() { return _name; }
|
||||
// Gets the Id of the Object
|
||||
public uint GetId() { return _id; }
|
||||
|
||||
// Gets the Permissions linked to this permission
|
||||
public List<uint> GetLinkedPermissions() { return _perms; }
|
||||
// Adds a new linked Permission
|
||||
public void AddLinkedPermission(uint id) { _perms.Add(id); }
|
||||
// Removes a linked Permission
|
||||
void RemoveLinkedPermission(uint id) { _perms.Remove(id); }
|
||||
|
||||
|
||||
uint _id; // id of the object
|
||||
string _name; // name of the object
|
||||
List<uint> _perms = new List<uint>(); // Set of permissions
|
||||
}
|
||||
|
||||
public enum RBACCommandResult
|
||||
{
|
||||
OK,
|
||||
CantAddAlreadyAdded,
|
||||
CantRevokeNotInList,
|
||||
InGrantedList,
|
||||
InDeniedList,
|
||||
IdDoesNotExists
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user