mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
528 lines
12 KiB
C++
528 lines
12 KiB
C++
#include "account_management.h"
|
|
#include "login_server.h"
|
|
#include "../common/event/task_scheduler.h"
|
|
#include "../common/event/event_loop.h"
|
|
#include "../common/net/dns.h"
|
|
#include "../common/strings.h"
|
|
|
|
extern LoginServer server;
|
|
EQ::Event::TaskScheduler task_runner;
|
|
|
|
/**
|
|
* @param username
|
|
* @param password
|
|
* @param email
|
|
* @param source_loginserver
|
|
* @param login_account_id
|
|
* @return
|
|
*/
|
|
int32 AccountManagement::CreateLoginServerAccount(
|
|
std::string username,
|
|
std::string password,
|
|
std::string email,
|
|
const std::string &source_loginserver,
|
|
uint32 login_account_id
|
|
)
|
|
{
|
|
auto mode = server.options.GetEncryptionMode();
|
|
auto hash = eqcrypt_hash(username, password, mode);
|
|
|
|
LogInfo(
|
|
"Attempting to create local login account for user [{0}] encryption algorithm [{1}] ({2})",
|
|
username,
|
|
GetEncryptionByModeId(mode),
|
|
mode
|
|
);
|
|
|
|
unsigned int db_id = 0;
|
|
if (server.db->DoesLoginServerAccountExist(username, hash, source_loginserver, 1)) {
|
|
LogWarning(
|
|
"Attempting to create local login account for user [{0}] login [{1}] but already exists!",
|
|
username,
|
|
source_loginserver
|
|
);
|
|
|
|
return -1;
|
|
}
|
|
|
|
uint32 created_account_id = 0;
|
|
if (login_account_id > 0) {
|
|
created_account_id = server.db->CreateLoginDataWithID(username, hash, source_loginserver, login_account_id);
|
|
}
|
|
else {
|
|
created_account_id = server.db->CreateLoginAccount(username, hash, source_loginserver, email);
|
|
}
|
|
|
|
if (created_account_id > 0) {
|
|
LogInfo(
|
|
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) id: [{3}]",
|
|
username,
|
|
GetEncryptionByModeId(mode),
|
|
mode,
|
|
created_account_id
|
|
);
|
|
|
|
return (int32) created_account_id;
|
|
}
|
|
|
|
LogError("Failed to create local login account for user [{0}]!", username);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @param username
|
|
* @param password
|
|
* @param email
|
|
* @return
|
|
*/
|
|
bool AccountManagement::CreateLoginserverWorldAdminAccount(
|
|
const std::string &username,
|
|
const std::string &password,
|
|
const std::string &email,
|
|
const std::string &first_name,
|
|
const std::string &last_name,
|
|
const std::string &ip_address
|
|
)
|
|
{
|
|
auto mode = server.options.GetEncryptionMode();
|
|
auto hash = eqcrypt_hash(username, password, mode);
|
|
|
|
LogInfo(
|
|
"Attempting to create world admin account | username [{0}] encryption algorithm [{1}] ({2})",
|
|
username,
|
|
GetEncryptionByModeId(mode),
|
|
mode
|
|
);
|
|
|
|
if (server.db->DoesLoginserverWorldAdminAccountExist(username)) {
|
|
LogWarning(
|
|
"Attempting to create world admin account for user [{0}] but already exists!",
|
|
username
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32 created_world_admin_id = server.db->CreateLoginserverWorldAdminAccount(
|
|
username,
|
|
hash,
|
|
first_name,
|
|
last_name,
|
|
email,
|
|
ip_address
|
|
);
|
|
|
|
if (created_world_admin_id > 0) {
|
|
LogInfo(
|
|
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) new admin id [{3}]",
|
|
username,
|
|
GetEncryptionByModeId(mode),
|
|
mode,
|
|
created_world_admin_id
|
|
);
|
|
return true;
|
|
}
|
|
|
|
LogError("Failed to create world admin account account for user [{0}]!", username);
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param in_account_username
|
|
* @param in_account_password
|
|
* @return
|
|
*/
|
|
uint32 AccountManagement::CheckLoginserverUserCredentials(
|
|
const std::string &in_account_username,
|
|
const std::string &in_account_password,
|
|
const std::string &source_loginserver
|
|
)
|
|
{
|
|
auto mode = server.options.GetEncryptionMode();
|
|
|
|
Database::DbLoginServerAccount
|
|
login_server_admin = server.db->GetLoginServerAccountByAccountName(
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
if (!login_server_admin.loaded) {
|
|
LogError(
|
|
"account [{0}] source_loginserver [{1}] not found!",
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool validated_credentials = eqcrypt_verify_hash(
|
|
in_account_username,
|
|
in_account_password,
|
|
login_server_admin.account_password,
|
|
mode
|
|
);
|
|
|
|
if (!validated_credentials) {
|
|
LogError(
|
|
"account [{0}] source_loginserver [{1}] invalid credentials!",
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LogInfo(
|
|
"account [{0}] source_loginserver [{1}] credentials validated success!",
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
return login_server_admin.id;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param in_account_username
|
|
* @param in_account_password
|
|
* @return
|
|
*/
|
|
bool AccountManagement::UpdateLoginserverUserCredentials(
|
|
const std::string &in_account_username,
|
|
const std::string &in_account_password,
|
|
const std::string &source_loginserver
|
|
)
|
|
{
|
|
auto mode = server.options.GetEncryptionMode();
|
|
|
|
Database::DbLoginServerAccount
|
|
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
if (!login_server_account.loaded) {
|
|
LogError(
|
|
"account [{0}] source_loginserver [{1}] not found!",
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
server.db->UpdateLoginserverAccountPasswordHash(
|
|
in_account_username,
|
|
source_loginserver,
|
|
eqcrypt_hash(
|
|
in_account_username,
|
|
in_account_password,
|
|
mode
|
|
)
|
|
);
|
|
|
|
LogInfo(
|
|
"account [{0}] source_loginserver [{1}] credentials updated!",
|
|
in_account_username,
|
|
source_loginserver
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param in_account_username
|
|
* @param in_account_password
|
|
*/
|
|
bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
|
|
const std::string &in_account_username,
|
|
const std::string &in_account_password
|
|
)
|
|
{
|
|
auto mode = server.options.GetEncryptionMode();
|
|
auto hash = eqcrypt_hash(in_account_username, in_account_password, mode);
|
|
|
|
bool updated_account = server.db->UpdateLoginWorldAdminAccountPasswordByUsername(
|
|
in_account_username,
|
|
hash
|
|
);
|
|
|
|
LogInfo(
|
|
"[{}] account_name [{}] status [{}]",
|
|
__func__,
|
|
in_account_username,
|
|
(updated_account ? "success" : "failed")
|
|
);
|
|
|
|
return updated_account;
|
|
}
|
|
|
|
/**
|
|
* @param in_account_id
|
|
* @param in_account_password_hash
|
|
*/
|
|
bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordById(
|
|
uint32 in_account_id,
|
|
const std::string &in_account_password_hash
|
|
)
|
|
{
|
|
bool updated_account = server.db->UpdateLoginWorldAdminAccountPassword(in_account_id, in_account_password_hash);
|
|
|
|
LogInfo(
|
|
"[{}] account_name [{}] status [{}]",
|
|
__func__,
|
|
in_account_id,
|
|
(updated_account ? "success" : "failed")
|
|
);
|
|
|
|
return updated_account;
|
|
}
|
|
|
|
constexpr int REQUEST_TIMEOUT_MS = 1500;
|
|
|
|
/**
|
|
* @param in_account_username
|
|
* @param in_account_password
|
|
* @return
|
|
*/
|
|
uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
|
const std::string &in_account_username,
|
|
const std::string &in_account_password
|
|
)
|
|
{
|
|
auto res = task_runner.Enqueue(
|
|
[&]() -> uint32 {
|
|
bool running = true;
|
|
uint32 ret = 0;
|
|
|
|
EQ::Net::DaybreakConnectionManager mgr;
|
|
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
|
|
|
mgr.OnNewConnection(
|
|
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
|
|
c = connection;
|
|
}
|
|
);
|
|
|
|
mgr.OnConnectionStateChange(
|
|
[&](
|
|
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
|
|
EQ::Net::DbProtocolStatus from,
|
|
EQ::Net::DbProtocolStatus to
|
|
) {
|
|
if (EQ::Net::StatusConnected == to) {
|
|
EQ::Net::DynamicPacket p;
|
|
p.PutUInt16(0, 1); //OP_SessionReady
|
|
p.PutUInt32(2, 2);
|
|
c->QueuePacket(p);
|
|
}
|
|
else if (EQ::Net::StatusDisconnected == to) {
|
|
running = false;
|
|
}
|
|
}
|
|
);
|
|
|
|
mgr.OnPacketRecv(
|
|
[&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
|
|
auto opcode = p.GetUInt16(0);
|
|
switch (opcode) {
|
|
case 0x0017: //OP_ChatMessage
|
|
{
|
|
size_t buffer_len =
|
|
in_account_username.length() + in_account_password.length() + 2;
|
|
|
|
std::unique_ptr<char[]> buffer(new char[buffer_len]);
|
|
|
|
strcpy(&buffer[0], in_account_username.c_str());
|
|
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
|
|
|
|
size_t encrypted_len = buffer_len;
|
|
|
|
if (encrypted_len % 8 > 0) {
|
|
encrypted_len = ((encrypted_len / 8) + 1) * 8;
|
|
}
|
|
|
|
EQ::Net::DynamicPacket p;
|
|
p.Resize(12 + encrypted_len);
|
|
p.PutUInt16(0, 2); //OP_Login
|
|
p.PutUInt32(2, 3);
|
|
|
|
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
|
|
c->QueuePacket(p);
|
|
break;
|
|
}
|
|
case 0x0018: {
|
|
auto encrypt_size = p.Length() - 12;
|
|
if (encrypt_size % 8 > 0) {
|
|
encrypt_size = (encrypt_size / 8) * 8;
|
|
}
|
|
|
|
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
|
|
|
|
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
|
|
|
|
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
|
|
auto response_error = sp.GetUInt16(1);
|
|
auto m_dbid = sp.GetUInt32(8);
|
|
|
|
{
|
|
ret = (response_error <= 101 ? m_dbid : 0);
|
|
running = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
auto s = Strings::Split(server.options.GetEQEmuLoginServerAddress(), ':');
|
|
if (s.size() == 2) {
|
|
auto address = s[0];
|
|
auto port = std::stoi(s[1]);
|
|
|
|
EQ::Net::DNSLookup(
|
|
address, port, false, [&](const std::string &addr) {
|
|
if (addr.empty()) {
|
|
ret = 0;
|
|
running = false;
|
|
}
|
|
|
|
mgr.Connect(addr, port);
|
|
}
|
|
);
|
|
}
|
|
|
|
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
|
|
|
auto &loop = EQ::EventLoop::Get();
|
|
while (running) {
|
|
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > REQUEST_TIMEOUT_MS) {
|
|
LogInfo("Deadline exceeded [{}]", REQUEST_TIMEOUT_MS);
|
|
running = false;
|
|
}
|
|
|
|
loop.Process();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
);
|
|
|
|
return res.get();
|
|
}
|
|
|
|
uint32 AccountManagement::HealthCheckUserLogin()
|
|
{
|
|
std::string in_account_username = "healthcheckuser";
|
|
std::string in_account_password = "healthcheckpassword";
|
|
|
|
auto res = task_runner.Enqueue(
|
|
[&]() -> uint32 {
|
|
bool running = true;
|
|
uint32 ret = 0;
|
|
|
|
EQ::Net::DaybreakConnectionManager mgr;
|
|
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
|
|
|
mgr.OnNewConnection(
|
|
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
|
|
c = connection;
|
|
}
|
|
);
|
|
|
|
mgr.OnConnectionStateChange(
|
|
[&](
|
|
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
|
|
EQ::Net::DbProtocolStatus from,
|
|
EQ::Net::DbProtocolStatus to
|
|
) {
|
|
if (EQ::Net::StatusConnected == to) {
|
|
EQ::Net::DynamicPacket p;
|
|
p.PutUInt16(0, 1); //OP_SessionReady
|
|
p.PutUInt32(2, 2);
|
|
c->QueuePacket(p);
|
|
}
|
|
else if (EQ::Net::StatusDisconnected == to) {
|
|
running = false;
|
|
}
|
|
}
|
|
);
|
|
|
|
mgr.OnPacketRecv(
|
|
[&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
|
|
auto opcode = p.GetUInt16(0);
|
|
switch (opcode) {
|
|
case 0x0017: //OP_ChatMessage
|
|
{
|
|
size_t buffer_len =
|
|
in_account_username.length() + in_account_password.length() + 2;
|
|
|
|
std::unique_ptr<char[]> buffer(new char[buffer_len]);
|
|
|
|
strcpy(&buffer[0], in_account_username.c_str());
|
|
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
|
|
|
|
size_t encrypted_len = buffer_len;
|
|
|
|
if (encrypted_len % 8 > 0) {
|
|
encrypted_len = ((encrypted_len / 8) + 1) * 8;
|
|
}
|
|
|
|
EQ::Net::DynamicPacket p;
|
|
p.Resize(12 + encrypted_len);
|
|
p.PutUInt16(0, 2); //OP_Login
|
|
p.PutUInt32(2, 3);
|
|
|
|
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
|
|
c->QueuePacket(p);
|
|
break;
|
|
}
|
|
case 0x0018: {
|
|
auto encrypt_size = p.Length() - 12;
|
|
if (encrypt_size % 8 > 0) {
|
|
encrypt_size = (encrypt_size / 8) * 8;
|
|
}
|
|
|
|
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
|
|
|
|
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
|
|
|
|
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
|
|
auto response_error = sp.GetUInt16(1);
|
|
|
|
{
|
|
// we only care to see the response code
|
|
ret = response_error;
|
|
running = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
mgr.Connect("127.0.0.1", 5999);
|
|
|
|
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
|
auto &loop = EQ::EventLoop::Get();
|
|
while (running) {
|
|
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 2000) {
|
|
ret = 0;
|
|
running = false;
|
|
}
|
|
|
|
loop.Process();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
);
|
|
|
|
return res.get();
|
|
}
|