mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Loginserver] Modernize codebase (#4647)
* Beginning of cleanup * More cleanup * More cleanup * Enc cleanup * client manager cleanup * client cleanup * More cleanup * More cleanup * Cleanup * More cleanup, account context, account management * Remove positional fmt bindings * Use LoginAccountContext * Update loginserver_webserver.cpp * Remove comments * Port CreateLoginServerAccount to repositories * More cleanup * More cleanup * More cleanup * More cleanup * Remove a ton of functions * More cleanup * More cleanup * More cleanup * Cleanup SendClientAuthToWorld * Consolidate world server logic * Update login_accounts_repository.h * Update login_accounts_repository.h * Move api tokens to repositories * Cleanup options * Move everything else to repositories * Update account_management.cpp * uint64 account * Update login_schema.sql * Fix * Update world_server.cpp * auto
This commit is contained in:
parent
1650efa787
commit
1a48add20e
@ -123,7 +123,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
{
|
||||
size_t current = 0;
|
||||
size_t total = m_buffer.size();
|
||||
constexpr size_t ls_info_size = sizeof(ServerNewLSInfo_Struct);
|
||||
constexpr size_t ls_info_size = sizeof(LoginserverNewWorldRequest);
|
||||
|
||||
while (current < total) {
|
||||
auto left = total - current;
|
||||
@ -138,7 +138,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
//this creates a small edge case where the exact size of a
|
||||
//packet from the modern protocol can't be "43061256"
|
||||
//so in send we pad it one byte if that's the case
|
||||
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
|
||||
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(LoginserverNewWorldRequest)) {
|
||||
m_legacy_mode = true;
|
||||
m_identifier = "World";
|
||||
m_parent->ConnectionIdentified(this);
|
||||
|
||||
@ -4,47 +4,94 @@
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_login_accounts_repository.h"
|
||||
#include "../../loginserver/encryption.h"
|
||||
#include "../../loginserver/login_types.h"
|
||||
|
||||
class LoginAccountsRepository: public BaseLoginAccountsRepository {
|
||||
class LoginAccountsRepository : public BaseLoginAccountsRepository {
|
||||
public:
|
||||
static int64 GetFreeID(Database &db, const std::string &loginserver)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT IFNULL(MAX(id), 0) + 1 FROM login_accounts WHERE source_loginserver = '{}'",
|
||||
Strings::Escape(loginserver)
|
||||
);
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* LoginAccountsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* LoginAccountsRepository::GetWhereNeverExpires()
|
||||
* LoginAccountsRepository::GetWhereXAndY()
|
||||
* LoginAccountsRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
auto results = db.QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Custom extended repository methods here
|
||||
auto row = results.begin();
|
||||
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
static LoginAccountsRepository::LoginAccounts CreateAccountFromContext(
|
||||
Database &db,
|
||||
LoginAccountContext c
|
||||
)
|
||||
{
|
||||
auto a = LoginAccountsRepository::NewEntity();
|
||||
|
||||
if (!c.password_is_encrypted) {
|
||||
auto e = EncryptPasswordFromContext(c);
|
||||
a.account_password = e.password;
|
||||
}
|
||||
|
||||
a.id = c.login_account_id > 0 ? c.login_account_id : GetFreeID(db, c.source_loginserver);
|
||||
a.account_name = c.username;
|
||||
a.account_email = !c.email.empty() ? c.email : "local_creation";
|
||||
a.source_loginserver = c.source_loginserver;
|
||||
a.last_ip_address = "127.0.0.1";
|
||||
a.last_login_date = std::time(nullptr);
|
||||
a.created_at = std::time(nullptr);
|
||||
LoginAccountsRepository::InsertOne(db, a);
|
||||
|
||||
return GetAccountFromContext(db, c).id > 0 ? a : NewEntity();
|
||||
}
|
||||
|
||||
static LoginAccountsRepository::LoginAccounts GetAccountFromContext(
|
||||
Database &db,
|
||||
LoginAccountContext c
|
||||
)
|
||||
{
|
||||
std::string where = fmt::format(
|
||||
"account_name = '{}' AND source_loginserver = '{}'",
|
||||
Strings::Escape(c.username),
|
||||
Strings::Escape(c.source_loginserver)
|
||||
);
|
||||
|
||||
if (!c.email.empty()) {
|
||||
where += fmt::format(" AND account_email = '{}'", Strings::Escape(c.email));
|
||||
}
|
||||
if (c.login_account_id > 0) {
|
||||
where += fmt::format(" AND id = {}", c.login_account_id);
|
||||
}
|
||||
|
||||
where += " LIMIT 1";
|
||||
|
||||
auto results = LoginAccountsRepository::GetWhere(db, where);
|
||||
|
||||
auto e = LoginAccountsRepository::NewEntity();
|
||||
if (results.size() == 1) {
|
||||
e = results.front();
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static LoginAccounts UpdateAccountPassword(Database &db, LoginAccounts a, std::string password)
|
||||
{
|
||||
LoginAccountContext c;
|
||||
c.username = a.account_name;
|
||||
c.password = password;
|
||||
auto e = EncryptPasswordFromContext(c);
|
||||
a.account_password = e.password;
|
||||
|
||||
int success = LoginAccountsRepository::UpdateOne(db, a);
|
||||
|
||||
return success ? a : NewEntity();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_LOGIN_ACCOUNTS_REPOSITORY_H
|
||||
|
||||
@ -5,46 +5,24 @@
|
||||
#include "../strings.h"
|
||||
#include "base/base_login_server_admins_repository.h"
|
||||
|
||||
class LoginServerAdminsRepository: public BaseLoginServerAdminsRepository {
|
||||
class LoginServerAdminsRepository : public BaseLoginServerAdminsRepository {
|
||||
public:
|
||||
static LoginServerAdmins GetByName(Database &db, std::string account_name)
|
||||
{
|
||||
auto admins = GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"account_name = '{}' LIMIT 1",
|
||||
Strings::Escape(account_name)
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* LoginServerAdminsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* LoginServerAdminsRepository::GetWhereNeverExpires()
|
||||
* LoginServerAdminsRepository::GetWhereXAndY()
|
||||
* LoginServerAdminsRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
if (admins.size() == 1) {
|
||||
return admins.front();
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_LOGIN_SERVER_ADMINS_REPOSITORY_H
|
||||
|
||||
@ -7,44 +7,27 @@
|
||||
|
||||
class LoginWorldServersRepository: public BaseLoginWorldServersRepository {
|
||||
public:
|
||||
static LoginWorldServers GetFromWorldContext(Database &db, LoginWorldContext c) {
|
||||
std::string where = fmt::format(
|
||||
"short_name = '{}' AND long_name = '{}'",
|
||||
Strings::Escape(c.short_name),
|
||||
Strings::Escape(c.long_name)
|
||||
);
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* LoginWorldServersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* LoginWorldServersRepository::GetWhereNeverExpires()
|
||||
* LoginWorldServersRepository::GetWhereXAndY()
|
||||
* LoginWorldServersRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
if (c.admin_id > 0) {
|
||||
where += fmt::format(" AND login_server_admin_id = {}", c.admin_id);
|
||||
}
|
||||
|
||||
// Custom extended repository methods here
|
||||
where += " LIMIT 1";
|
||||
|
||||
auto results = GetWhere(db, where);
|
||||
auto e = NewEntity();
|
||||
if (results.size() == 1) {
|
||||
e = results.front();
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_LOGIN_WORLD_SERVERS_REPOSITORY_H
|
||||
|
||||
@ -646,7 +646,7 @@ struct ServerLSInfo_Struct {
|
||||
uint8 servertype; // 0=world, 1=chat, 2=login, 3=MeshLogin
|
||||
};
|
||||
|
||||
struct ServerNewLSInfo_Struct {
|
||||
struct LoginserverNewWorldRequest {
|
||||
char server_long_name[201]; // name the worldserver wants
|
||||
char server_short_name[50]; // shortname the worldserver wants
|
||||
char remote_ip_address[125]; // DNS address of the server
|
||||
@ -658,21 +658,21 @@ struct ServerNewLSInfo_Struct {
|
||||
uint8 server_process_type; // 0=world, 1=chat, 2=login, 3=MeshLogin
|
||||
};
|
||||
|
||||
struct ServerLSAccountUpdate_Struct { // for updating info on login server
|
||||
char worldaccount[31]; // account name for the worldserver
|
||||
char worldpassword[31]; // password for the name
|
||||
uint32 useraccountid; // player account ID
|
||||
char useraccount[31]; // player account name
|
||||
char userpassword[51]; // player account password
|
||||
char user_email[101]; // player account email address
|
||||
struct LoginserverAccountUpdate { // for updating info on login server
|
||||
char world_account[31]; // account name for the worldserver
|
||||
char world_password[31]; // password for the name
|
||||
uint32 user_account_id; // player account ID
|
||||
char user_account_name[31]; // player account name
|
||||
char user_account_password[51]; // player account password
|
||||
char user_email[101]; // player account email address
|
||||
};
|
||||
|
||||
struct ServerLSStatus_Struct {
|
||||
struct LoginserverWorldStatusUpdate {
|
||||
int32 status;
|
||||
int32 num_players;
|
||||
int32 num_zones;
|
||||
};
|
||||
struct ZoneInfo_Struct {
|
||||
struct LoginserverZoneInfoUpdate {
|
||||
uint32 zone;
|
||||
uint16 count;
|
||||
uint32 zone_wid;
|
||||
|
||||
@ -4,12 +4,11 @@ SET(eqlogin_sources
|
||||
account_management.cpp
|
||||
client.cpp
|
||||
client_manager.cpp
|
||||
database.cpp
|
||||
encryption.cpp
|
||||
loginserver_command_handler.cpp
|
||||
loginserver_webserver.cpp
|
||||
main.cpp
|
||||
server_manager.cpp
|
||||
world_server_manager.cpp
|
||||
world_server.cpp
|
||||
)
|
||||
|
||||
@ -17,14 +16,13 @@ SET(eqlogin_headers
|
||||
account_management.h
|
||||
client.h
|
||||
client_manager.h
|
||||
database.h
|
||||
encryption.h
|
||||
loginserver_command_handler.h
|
||||
loginserver_webserver.h
|
||||
login_server.h
|
||||
login_types.h
|
||||
options.h
|
||||
server_manager.h
|
||||
world_server_manager.h
|
||||
world_server.h
|
||||
)
|
||||
|
||||
|
||||
@ -1,259 +1,114 @@
|
||||
#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"
|
||||
#include "../common/repositories/login_accounts_repository.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
|
||||
)
|
||||
uint64 AccountManagement::CreateLoginServerAccount(LoginAccountContext c)
|
||||
{
|
||||
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)) {
|
||||
if (LoginAccountsRepository::GetAccountFromContext(database, c).id > 0) {
|
||||
LogWarning(
|
||||
"Attempting to create local login account for user [{0}] login [{1}] but already exists!",
|
||||
username,
|
||||
source_loginserver
|
||||
"Attempting to create local login account for user [{}] but already exists!",
|
||||
c.username
|
||||
);
|
||||
|
||||
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);
|
||||
auto a = LoginAccountsRepository::CreateAccountFromContext(database, c);
|
||||
if (a.id > 0) {
|
||||
return (int64) a.id;
|
||||
}
|
||||
|
||||
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);
|
||||
LogError("Failed to create local login account for user [{}] !", c.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
|
||||
)
|
||||
uint64 AccountManagement::CheckLoginserverUserCredentials(LoginAccountContext c)
|
||||
{
|
||||
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) {
|
||||
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
|
||||
if (!a.id) {
|
||||
LogError(
|
||||
"account [{0}] source_loginserver [{1}] not found!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
"account [{}] source_loginserver [{}] not found!",
|
||||
c.username,
|
||||
c.source_loginserver
|
||||
);
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool validated_credentials = eqcrypt_verify_hash(
|
||||
in_account_username,
|
||||
in_account_password,
|
||||
login_server_admin.account_password,
|
||||
mode
|
||||
);
|
||||
|
||||
bool validated_credentials = eqcrypt_verify_hash(c.username, c.password, a.account_password, mode);
|
||||
if (!validated_credentials) {
|
||||
LogError(
|
||||
"account [{0}] source_loginserver [{1}] invalid credentials!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
"account [{}] source_loginserver [{}] invalid credentials!",
|
||||
c.username,
|
||||
c.source_loginserver
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"account [{0}] source_loginserver [{1}] credentials validated success!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
"account [{}] source_loginserver [{}] credentials validated success!",
|
||||
c.username,
|
||||
c.source_loginserver
|
||||
);
|
||||
|
||||
return login_server_admin.id;
|
||||
return a.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
|
||||
)
|
||||
bool AccountManagement::UpdateLoginserverUserCredentials(LoginAccountContext c)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
if (!login_server_account.loaded) {
|
||||
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
|
||||
if (!a.id) {
|
||||
LogError(
|
||||
"account [{0}] source_loginserver [{1}] not found!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
"account [{}] source_loginserver [{}] not found!",
|
||||
c.username,
|
||||
c.source_loginserver
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
server.db->UpdateLoginserverAccountPasswordHash(
|
||||
in_account_username,
|
||||
source_loginserver,
|
||||
eqcrypt_hash(
|
||||
in_account_username,
|
||||
in_account_password,
|
||||
mode
|
||||
)
|
||||
);
|
||||
LoginAccountsRepository::UpdateAccountPassword(database, a, c.password);
|
||||
|
||||
LogInfo(
|
||||
"account [{0}] source_loginserver [{1}] credentials updated!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
"account [{}] source_loginserver [{}] credentials updated!",
|
||||
c.username,
|
||||
c.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
|
||||
)
|
||||
bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(LoginAccountContext c)
|
||||
{
|
||||
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
|
||||
auto hash = eqcrypt_hash(
|
||||
c.username,
|
||||
c.password,
|
||||
mode
|
||||
);
|
||||
|
||||
auto a = LoginServerAdminsRepository::GetByName(database, c.username);
|
||||
if (!a.id) {
|
||||
LogError(
|
||||
"account_name [{}] not found!",
|
||||
c.username
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
a.account_password = hash;
|
||||
auto updated_account = LoginServerAdminsRepository::UpdateOne(database, a);
|
||||
|
||||
LogInfo(
|
||||
"[{}] account_name [{}] status [{}]",
|
||||
__func__,
|
||||
in_account_username,
|
||||
"account_name [{}] status [{}]",
|
||||
c.username,
|
||||
(updated_account ? "success" : "failed")
|
||||
);
|
||||
|
||||
@ -262,15 +117,7 @@ bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
|
||||
|
||||
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
|
||||
)
|
||||
uint64 AccountManagement::CheckExternalLoginserverUserCredentials(LoginAccountContext c)
|
||||
{
|
||||
auto res = task_runner.Enqueue(
|
||||
[&]() -> uint32 {
|
||||
@ -278,11 +125,11 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
uint32 ret = 0;
|
||||
|
||||
EQ::Net::DaybreakConnectionManager mgr;
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> conn;
|
||||
|
||||
mgr.OnNewConnection(
|
||||
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
|
||||
c = connection;
|
||||
conn = connection;
|
||||
}
|
||||
);
|
||||
|
||||
@ -296,7 +143,7 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
EQ::Net::DynamicPacket p;
|
||||
p.PutUInt16(0, 1); //OP_SessionReady
|
||||
p.PutUInt32(2, 2);
|
||||
c->QueuePacket(p);
|
||||
conn->QueuePacket(p);
|
||||
}
|
||||
else if (EQ::Net::StatusDisconnected == to) {
|
||||
running = false;
|
||||
@ -310,13 +157,12 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
switch (opcode) {
|
||||
case 0x0017: //OP_ChatMessage
|
||||
{
|
||||
size_t buffer_len =
|
||||
in_account_username.length() + in_account_password.length() + 2;
|
||||
size_t buffer_len = c.username.length() + c.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());
|
||||
strcpy(&buffer[0], c.username.c_str());
|
||||
strcpy(&buffer[c.username.length() + 1], c.password.c_str());
|
||||
|
||||
size_t encrypted_len = buffer_len;
|
||||
|
||||
@ -330,11 +176,11 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
p.PutUInt32(2, 3);
|
||||
|
||||
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
|
||||
c->QueuePacket(p);
|
||||
conn->QueuePacket(p);
|
||||
break;
|
||||
}
|
||||
case 0x0018: {
|
||||
auto encrypt_size = p.Length() - 12;
|
||||
auto encrypt_size = p.Length() - 12;
|
||||
if (encrypt_size % 8 > 0) {
|
||||
encrypt_size = (encrypt_size / 8) * 8;
|
||||
}
|
||||
@ -394,15 +240,15 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
return res.get();
|
||||
}
|
||||
|
||||
uint32 AccountManagement::HealthCheckUserLogin()
|
||||
uint64 AccountManagement::HealthCheckUserLogin()
|
||||
{
|
||||
std::string in_account_username = "healthcheckuser";
|
||||
std::string in_account_password = "healthcheckpassword";
|
||||
|
||||
auto res = task_runner.Enqueue(
|
||||
[&]() -> uint32 {
|
||||
[&]() -> uint64 {
|
||||
bool running = true;
|
||||
uint32 ret = 0;
|
||||
uint64 ret = 0;
|
||||
|
||||
EQ::Net::DaybreakConnectionManager mgr;
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
||||
@ -461,7 +307,7 @@ uint32 AccountManagement::HealthCheckUserLogin()
|
||||
break;
|
||||
}
|
||||
case 0x0018: {
|
||||
auto encrypt_size = p.Length() - 12;
|
||||
auto encrypt_size = p.Length() - 12;
|
||||
if (encrypt_size % 8 > 0) {
|
||||
encrypt_size = (encrypt_size / 8) * 8;
|
||||
}
|
||||
@ -487,11 +333,11 @@ uint32 AccountManagement::HealthCheckUserLogin()
|
||||
mgr.Connect("127.0.0.1", 5999);
|
||||
|
||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||
auto &loop = EQ::EventLoop::Get();
|
||||
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;
|
||||
ret = 0;
|
||||
running = false;
|
||||
}
|
||||
|
||||
@ -504,3 +350,59 @@ uint32 AccountManagement::HealthCheckUserLogin()
|
||||
|
||||
return res.get();
|
||||
}
|
||||
|
||||
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 [{}] encryption algorithm [{}] ({})",
|
||||
username,
|
||||
GetEncryptionByModeId(mode),
|
||||
mode
|
||||
);
|
||||
|
||||
auto a = LoginServerAdminsRepository::GetByName(database, username);
|
||||
if (a.id > 0) {
|
||||
LogWarning(
|
||||
"Attempting to create world admin account for user [{}] but already exists!",
|
||||
username
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
a = LoginServerAdminsRepository::NewEntity();
|
||||
a.account_name = username;
|
||||
a.account_password = hash;
|
||||
a.first_name = first_name;
|
||||
a.last_name = last_name;
|
||||
a.email = email;
|
||||
a.registration_ip_address = ip_address;
|
||||
a.registration_date = std::time(nullptr);
|
||||
|
||||
a = LoginServerAdminsRepository::InsertOne(database, a);
|
||||
|
||||
if (a.id > 0) {
|
||||
LogInfo(
|
||||
"Account creation success for user [{}] encryption algorithm [{}] ({}) new admin id [{}]",
|
||||
username,
|
||||
GetEncryptionByModeId(mode),
|
||||
mode,
|
||||
a.id
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
LogError("Failed to create world admin account account for user [{}] !", username);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3,32 +3,22 @@
|
||||
|
||||
#include "iostream"
|
||||
#include "../common/types.h"
|
||||
#include "login_types.h"
|
||||
#include "encryption.h"
|
||||
#include "login_server.h"
|
||||
|
||||
extern LoginServer server;
|
||||
extern Database database;
|
||||
|
||||
class AccountManagement {
|
||||
public:
|
||||
static uint64 CreateLoginServerAccount(LoginAccountContext c);
|
||||
static uint64 CheckLoginserverUserCredentials(LoginAccountContext c);
|
||||
static bool UpdateLoginserverUserCredentials(LoginAccountContext c);
|
||||
static uint64 CheckExternalLoginserverUserCredentials(LoginAccountContext c);
|
||||
static bool UpdateLoginserverWorldAdminAccountPasswordByName(LoginAccountContext c);
|
||||
static uint64 HealthCheckUserLogin();
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param email
|
||||
* @param source_loginserver
|
||||
* @param login_account_id
|
||||
* @return
|
||||
*/
|
||||
static int32 CreateLoginServerAccount(
|
||||
std::string username,
|
||||
std::string password,
|
||||
std::string email = "",
|
||||
const std::string &source_loginserver = "local",
|
||||
uint32 login_account_id = 0
|
||||
);
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
static bool CreateLoginserverWorldAdminAccount(
|
||||
const std::string &username,
|
||||
const std::string &password,
|
||||
@ -37,50 +27,6 @@ public:
|
||||
const std::string &last_name = "",
|
||||
const std::string &ip_address = ""
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static uint32 CheckLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password,
|
||||
const std::string &source_loginserver = "local"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static bool UpdateLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password,
|
||||
const std::string &source_loginserver = "local"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static uint32 CheckExternalLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static bool UpdateLoginserverWorldAdminAccountPasswordByName(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password
|
||||
);
|
||||
|
||||
static uint32 HealthCheckUserLogin();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,25 +1,18 @@
|
||||
#include "client.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/strings.h"
|
||||
#include "encryption.h"
|
||||
#include "account_management.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
/**
|
||||
* @param c
|
||||
* @param v
|
||||
*/
|
||||
Client::Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v)
|
||||
{
|
||||
m_connection = c;
|
||||
m_client_version = v;
|
||||
m_client_status = cs_not_sent_session_ready;
|
||||
m_account_id = 0;
|
||||
m_play_server_id = 0;
|
||||
m_play_sequence_id = 0;
|
||||
m_connection = c;
|
||||
m_client_version = v;
|
||||
m_client_status = cs_not_sent_session_ready;
|
||||
m_account_id = 0;
|
||||
m_selected_play_server_id = 0;
|
||||
m_play_sequence_id = 0;
|
||||
}
|
||||
|
||||
bool Client::Process()
|
||||
@ -43,8 +36,8 @@ bool Client::Process()
|
||||
|
||||
switch (app->GetOpcode()) {
|
||||
case OP_SessionReady: {
|
||||
LogInfo("Session ready received from client account {}", GetClientDescription());
|
||||
Handle_SessionReady((const char *) app->pBuffer, app->Size());
|
||||
LogInfo("Session ready received from client account {}", GetClientLoggingDescription());
|
||||
HandleSessionReady((const char *) app->pBuffer, app->Size());
|
||||
break;
|
||||
}
|
||||
case OP_Login: {
|
||||
@ -53,9 +46,9 @@ bool Client::Process()
|
||||
break;
|
||||
}
|
||||
|
||||
LogInfo("Login received from client {}", GetClientDescription());
|
||||
LogInfo("Login received from client {}", GetClientLoggingDescription());
|
||||
|
||||
Handle_Login((const char *) app->pBuffer, app->Size());
|
||||
HandleLogin((const char *) app->pBuffer, app->Size());
|
||||
break;
|
||||
}
|
||||
case OP_ServerListRequest: {
|
||||
@ -64,18 +57,18 @@ bool Client::Process()
|
||||
break;
|
||||
}
|
||||
|
||||
LogInfo("Server list request received from client {}", GetClientDescription());
|
||||
LogInfo("Server list request received from client {}", GetClientLoggingDescription());
|
||||
|
||||
SendServerListPacket(*(uint32_t *) app->pBuffer);
|
||||
break;
|
||||
}
|
||||
case OP_PlayEverquestRequest: {
|
||||
if (app->Size() < sizeof(PlayEverquestRequest_Struct)) {
|
||||
if (app->Size() < sizeof(PlayEverquestRequest)) {
|
||||
LogError("Play received but it is too small, discarding");
|
||||
break;
|
||||
}
|
||||
|
||||
Handle_Play((const char *) app->pBuffer);
|
||||
SendPlayToWorld((const char *) app->pBuffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -87,13 +80,7 @@ bool Client::Process()
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends our reply to session ready packet
|
||||
*
|
||||
* @param data
|
||||
* @param size
|
||||
*/
|
||||
void Client::Handle_SessionReady(const char *data, unsigned int size)
|
||||
void Client::HandleSessionReady(const char *data, unsigned int size)
|
||||
{
|
||||
if (m_client_status != cs_not_sent_session_ready) {
|
||||
LogError("Session ready received again after already being received");
|
||||
@ -107,11 +94,8 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
|
||||
|
||||
m_client_status = cs_waiting_for_login;
|
||||
|
||||
/**
|
||||
* The packets are identical between the two versions
|
||||
*/
|
||||
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply_Struct));
|
||||
auto buf = reinterpret_cast<LoginHandShakeReply_Struct*>(outapp->pBuffer);
|
||||
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply));
|
||||
auto buf = reinterpret_cast<LoginHandShakeReply *>(outapp->pBuffer);
|
||||
buf->base_header.sequence = 0x02;
|
||||
buf->base_reply.success = true;
|
||||
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
|
||||
@ -120,13 +104,7 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
|
||||
delete outapp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies login and send a reply
|
||||
*
|
||||
* @param data
|
||||
* @param size
|
||||
*/
|
||||
void Client::Handle_Login(const char *data, unsigned int size)
|
||||
void Client::HandleLogin(const char *data, unsigned int size)
|
||||
{
|
||||
if (m_client_status != cs_waiting_for_login) {
|
||||
LogError("Login received after already having logged in");
|
||||
@ -134,41 +112,37 @@ void Client::Handle_Login(const char *data, unsigned int size)
|
||||
}
|
||||
|
||||
// login user/pass are variable length after unencrypted opcode and base message header (size includes opcode)
|
||||
constexpr int header_size = sizeof(uint16_t) + sizeof(LoginBaseMessage_Struct);
|
||||
int data_size = size - header_size;
|
||||
constexpr int header_size = sizeof(uint16_t) + sizeof(LoginBaseMessage);
|
||||
int data_size = size - header_size;
|
||||
|
||||
if (size <= header_size) {
|
||||
LogError("Login received packet of size: {0}, this would cause a buffer overflow, discarding", size);
|
||||
LogError("Login received packet of size: {}, this would cause a buffer overflow, discarding", size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_size % 8 != 0) {
|
||||
LogError("Login received packet of size: {0}, this would cause a block corruption, discarding", size);
|
||||
LogError("Login received packet of size: {}, this would cause a block corruption, discarding", size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char *login_packet_buffer = nullptr;
|
||||
|
||||
unsigned int db_account_id = 0;
|
||||
|
||||
std::string db_loginserver = "local";
|
||||
if (server.options.CanAutoLinkAccounts()) {
|
||||
if (std::getenv("LSPX")) {
|
||||
db_loginserver = "eqemu";
|
||||
}
|
||||
|
||||
std::string db_account_password_hash;
|
||||
|
||||
std::string outbuffer;
|
||||
outbuffer.resize(data_size);
|
||||
if (outbuffer.length() == 0) {
|
||||
if (outbuffer.empty()) {
|
||||
LogError("Corrupt buffer sent to server, no length");
|
||||
return;
|
||||
}
|
||||
|
||||
// data starts at base message header (opcode not included)
|
||||
auto r = eqcrypt_block(data + sizeof(LoginBaseMessage_Struct), data_size, &outbuffer[0], 0);
|
||||
auto r = eqcrypt_block(data + sizeof(LoginBaseMessage), data_size, &outbuffer[0], false);
|
||||
if (r == nullptr) {
|
||||
LogError("Failed to decrypt eqcrypt block");
|
||||
return;
|
||||
@ -182,131 +156,114 @@ void Client::Handle_Login(const char *data, unsigned int size)
|
||||
return;
|
||||
}
|
||||
|
||||
// std::cout << "User: " << user << std::endl;
|
||||
|
||||
// only need to copy the base header for reply options, ignore login info
|
||||
memcpy(&m_llrs, data, sizeof(LoginBaseMessage_Struct));
|
||||
memcpy(&m_login_base_message, data, sizeof(LoginBaseMessage));
|
||||
|
||||
bool result = false;
|
||||
if (outbuffer[0] == 0 && outbuffer[1] == 0) {
|
||||
// std::cout << "Seq: " << m_login_base_message.sequence << std::endl;
|
||||
// std::cout << "compressed: " << m_login_base_message.compressed << std::endl;
|
||||
// std::cout << "encrypt_type: " << m_login_base_message.encrypt_type << std::endl;
|
||||
// std::cout << "unk3: " << m_login_base_message.unk3 << std::endl;
|
||||
|
||||
bool login_success = false;
|
||||
bool token_login = outbuffer[0] == 0 && outbuffer[1] == 0;
|
||||
if (token_login) {
|
||||
if (server.options.IsTokenLoginAllowed()) {
|
||||
cred = (&outbuffer[2 + user.length()]);
|
||||
result = server.db->GetLoginTokenDataFromToken(
|
||||
cred,
|
||||
m_connection->GetRemoteAddr(),
|
||||
db_account_id,
|
||||
db_loginserver,
|
||||
user
|
||||
);
|
||||
cred = (&outbuffer[2 + user.length()]);
|
||||
// todo: implement token login
|
||||
// SELECT login_server, username, account_id FROM login_tickets WHERE expires > NOW() AND id='{}' AND ip_address='{}' LIMIT 1
|
||||
// login_success ? DoSuccessfulLogin(user, db_account_id, db_loginserver) : SendFailedLogin();
|
||||
SendFailedLogin();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (server.options.IsPasswordLoginAllowed()) {
|
||||
cred = (&outbuffer[1 + user.length()]);
|
||||
auto components = Strings::Split(user, ':');
|
||||
if (components.size() == 2) {
|
||||
db_loginserver = components[0];
|
||||
user = components[1];
|
||||
}
|
||||
|
||||
// health checks
|
||||
if (ProcessHealthCheck(user)) {
|
||||
DoFailedLogin();
|
||||
return;
|
||||
}
|
||||
// normal login
|
||||
cred = (&outbuffer[1 + user.length()]);
|
||||
auto components = Strings::Split(user, ':');
|
||||
if (components.size() == 2) {
|
||||
db_loginserver = components[0];
|
||||
user = components[1];
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Attempting password based login [{0}] login [{1}]",
|
||||
user,
|
||||
db_loginserver
|
||||
);
|
||||
// health checks
|
||||
if (ProcessHealthCheck(user)) {
|
||||
SendFailedLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
ParseAccountString(user, user, db_loginserver);
|
||||
LogInfo(
|
||||
"Attempting password based login [{}] login [{}]",
|
||||
user,
|
||||
db_loginserver
|
||||
);
|
||||
|
||||
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
|
||||
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
|
||||
ParseAccountString(user, user, db_loginserver);
|
||||
|
||||
#ifdef LSPX
|
||||
// if user updated their password on the login server, update it here by validating their credentials with the login server
|
||||
if (!result && db_loginserver == "eqemu") {
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(user, cred);
|
||||
if (account_id > 0) {
|
||||
auto encryption_mode = server.options.GetEncryptionMode();
|
||||
server.db->UpdateLoginserverAccountPasswordHash(
|
||||
user,
|
||||
db_loginserver,
|
||||
eqcrypt_hash(user, cred, encryption_mode)
|
||||
);
|
||||
LogInfo("Updating eqemu account [{}] password hash", account_id);
|
||||
result = true;
|
||||
}
|
||||
LoginAccountContext c = {};
|
||||
c.username = user;
|
||||
c.password = cred;
|
||||
c.source_loginserver = db_loginserver;
|
||||
|
||||
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
|
||||
if (a.id > 0) {
|
||||
login_success = VerifyAndUpdateLoginHash(c, a);
|
||||
|
||||
// if user updated their password on the login server, update it here by validating their credentials with the login server
|
||||
if (std::getenv("LSPX") && !login_success && db_loginserver == "eqemu") {
|
||||
LogInfo("LSPX | Attempting login account via [{}]", db_loginserver);
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(c);
|
||||
LogInfo("LSPX | External login account id [{}]", account_id);
|
||||
if (account_id > 0) {
|
||||
auto updated_account = LoginAccountsRepository::UpdateAccountPassword(database, a, cred);
|
||||
if (!updated_account.id) {
|
||||
LogError("Failed to update eqemu account [{}] password hash", account_id);
|
||||
SendFailedLogin();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
LogDebug("Success [{0}]", (result ? "true" : "false"));
|
||||
}
|
||||
else {
|
||||
m_client_status = cs_creating_account;
|
||||
AttemptLoginAccountCreation(user, cred, db_loginserver);
|
||||
|
||||
LogInfo("Updating eqemu account [{}] password hash", account_id);
|
||||
DoSuccessfulLogin(updated_account);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("Successful login [{}]", (login_success ? "true" : "false"));
|
||||
login_success ? DoSuccessfulLogin(a) : SendFailedLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login accepted
|
||||
*/
|
||||
if (result) {
|
||||
LogInfo(
|
||||
"login [{0}] user [{1}] Login succeeded",
|
||||
db_loginserver,
|
||||
user
|
||||
);
|
||||
|
||||
DoSuccessfulLogin(user, db_account_id, db_loginserver);
|
||||
}
|
||||
else {
|
||||
LogInfo(
|
||||
"login [{0}] user [{1}] Login failed",
|
||||
db_loginserver,
|
||||
user
|
||||
);
|
||||
|
||||
DoFailedLogin();
|
||||
}
|
||||
// if we are here, the account does not exist
|
||||
m_client_status = cs_creating_account;
|
||||
AttemptLoginAccountCreation(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the requested server to see if the client is allowed or not
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void Client::Handle_Play(const char *data)
|
||||
void Client::SendPlayToWorld(const char *data)
|
||||
{
|
||||
if (m_client_status != cs_logged_in) {
|
||||
LogError("Client sent a play request when they were not logged in, discarding");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *play = (const PlayEverquestRequest_Struct *) data;
|
||||
const auto *play = (const PlayEverquestRequest *) data;
|
||||
auto server_id_in = (unsigned int) play->server_number;
|
||||
auto sequence_in = (unsigned int) play->base_header.sequence;
|
||||
|
||||
LogInfo(
|
||||
"[Handle_Play] Play received from client [{}] server number [{}] sequence [{}]",
|
||||
"[SendPlayToWorld] Play received from client [{}] server number [{}] sequence [{}]",
|
||||
GetAccountName(),
|
||||
server_id_in,
|
||||
sequence_in
|
||||
);
|
||||
|
||||
m_play_server_id = (unsigned int) play->server_number;
|
||||
m_play_sequence_id = sequence_in;
|
||||
m_play_server_id = server_id_in;
|
||||
server.server_manager->SendUserToWorldRequest(server_id_in, m_account_id, m_loginserver_name);
|
||||
m_selected_play_server_id = (unsigned int) play->server_number;
|
||||
m_play_sequence_id = sequence_in;
|
||||
m_selected_play_server_id = server_id_in;
|
||||
server.server_manager->SendUserLoginToWorldRequest(server_id_in, m_account_id, m_loginserver_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param seq
|
||||
*/
|
||||
void Client::SendServerListPacket(uint32 seq)
|
||||
{
|
||||
auto app = server.server_manager->CreateServerListPacket(this, seq);
|
||||
@ -316,11 +273,11 @@ void Client::SendServerListPacket(uint32 seq)
|
||||
|
||||
void Client::SendPlayResponse(EQApplicationPacket *outapp)
|
||||
{
|
||||
LogInfo("Sending play response for {}", GetClientDescription());
|
||||
LogInfo("Sending play response for {}", GetClientLoggingDescription());
|
||||
m_connection->QueuePacket(outapp);
|
||||
}
|
||||
|
||||
void Client::GenerateKey()
|
||||
void Client::GenerateRandomLoginKey()
|
||||
{
|
||||
m_key.clear();
|
||||
int count = 0;
|
||||
@ -339,229 +296,193 @@ void Client::GenerateKey()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param loginserver
|
||||
*/
|
||||
void Client::AttemptLoginAccountCreation(
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
const std::string &loginserver
|
||||
)
|
||||
void Client::AttemptLoginAccountCreation(LoginAccountContext c)
|
||||
{
|
||||
LogInfo("user [{}] loginserver [{}]", user, loginserver);
|
||||
LogInfo("user [{}] loginserver [{}]", c.username, c.source_loginserver);
|
||||
|
||||
#ifdef LSPX
|
||||
if (loginserver == "eqemu") {
|
||||
LogInfo("Attempting login account creation via '{0}'", loginserver);
|
||||
|
||||
if (!server.options.CanAutoLinkAccounts()) {
|
||||
LogInfo("CanAutoLinkAccounts disabled - sending failed login");
|
||||
DoFailedLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
user,
|
||||
pass
|
||||
);
|
||||
if (std::getenv("LSPX") && c.source_loginserver == "eqemu") {
|
||||
LogInfo("LSPX | Attempting login account creation via [{}]", c.source_loginserver);
|
||||
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(c);
|
||||
c.login_account_id = account_id;
|
||||
if (account_id > 0) {
|
||||
LogInfo("Found and creating eqemu account [{}]", account_id);
|
||||
CreateEQEmuAccount(user, pass, account_id);
|
||||
LogInfo("LSPX | Found and creating eqemu account [{}]", account_id);
|
||||
auto a = LoginAccountsRepository::CreateAccountFromContext(database, c);
|
||||
if (a.id > 0) {
|
||||
DoSuccessfulLogin(a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("LSPX | External authentication failed for user [{}]", c.username);
|
||||
|
||||
SendFailedLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.options.CanAutoCreateAccounts() && c.source_loginserver == "local") {
|
||||
LogInfo("CanAutoCreateAccounts enabled, attempting to crate account [{}]", c.username);
|
||||
auto a = LoginAccountsRepository::CreateAccountFromContext(database, c);
|
||||
if (a.id > 0) {
|
||||
DoSuccessfulLogin(a);
|
||||
return;
|
||||
}
|
||||
|
||||
DoFailedLogin();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (server.options.CanAutoCreateAccounts() && loginserver == "local") {
|
||||
LogInfo("CanAutoCreateAccounts enabled, attempting to creating account [{0}]", user);
|
||||
CreateLocalAccount(user, pass);
|
||||
return;
|
||||
}
|
||||
|
||||
DoFailedLogin();
|
||||
SendFailedLogin();
|
||||
}
|
||||
|
||||
void Client::DoFailedLogin()
|
||||
void Client::SendFailedLogin()
|
||||
{
|
||||
m_stored_user.clear();
|
||||
m_stored_pass.clear();
|
||||
m_stored_username.clear();
|
||||
m_stored_password.clear();
|
||||
|
||||
// unencrypted
|
||||
LoginBaseMessage_Struct base_header{};
|
||||
base_header.sequence = m_llrs.sequence; // login (3)
|
||||
base_header.encrypt_type = m_llrs.encrypt_type;
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence; // login (3)
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
|
||||
// encrypted
|
||||
PlayerLoginReply_Struct login_reply{};
|
||||
login_reply.base_reply.success = false;
|
||||
login_reply.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = false;
|
||||
r.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
|
||||
|
||||
char encrypted_buffer[80] = {0};
|
||||
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
|
||||
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block for failed login");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
|
||||
outapp.WriteData(&base_header, sizeof(base_header));
|
||||
outapp.WriteData(&h, sizeof(h));
|
||||
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(&outapp);
|
||||
m_client_status = cs_failed_to_login;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a login hash, will also attempt to update a login hash if needed
|
||||
*
|
||||
* @param account_username
|
||||
* @param source_loginserver
|
||||
* @param account_password
|
||||
* @param password_hash
|
||||
* @return
|
||||
*/
|
||||
bool Client::VerifyLoginHash(
|
||||
const std::string &account_username,
|
||||
const std::string &source_loginserver,
|
||||
const std::string &account_password,
|
||||
const std::string &password_hash
|
||||
)
|
||||
bool Client::VerifyAndUpdateLoginHash(LoginAccountContext c, const LoginAccountsRepository::LoginAccounts &a)
|
||||
{
|
||||
auto encryption_mode = server.options.GetEncryptionMode();
|
||||
if (eqcrypt_verify_hash(account_username, account_password, password_hash, encryption_mode)) {
|
||||
if (eqcrypt_verify_hash(a.account_name, c.password, a.account_password, encryption_mode)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (server.options.IsUpdatingInsecurePasswords()) {
|
||||
if (encryption_mode < EncryptionModeArgon2) {
|
||||
encryption_mode = EncryptionModeArgon2;
|
||||
}
|
||||
|
||||
uint32 insecure_source_encryption_mode = 0;
|
||||
if (password_hash.length() == CryptoHash::md5_hash_length) {
|
||||
for (int i = EncryptionModeMD5; i <= EncryptionModeMD5Triple; ++i) {
|
||||
if (i != encryption_mode &&
|
||||
eqcrypt_verify_hash(account_username, account_password, password_hash, i)) {
|
||||
insecure_source_encryption_mode = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (password_hash.length() == CryptoHash::sha1_hash_length && insecure_source_encryption_mode == 0) {
|
||||
for (int i = EncryptionModeSHA; i <= EncryptionModeSHATriple; ++i) {
|
||||
if (i != encryption_mode &&
|
||||
eqcrypt_verify_hash(account_username, account_password, password_hash, i)) {
|
||||
insecure_source_encryption_mode = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (password_hash.length() == CryptoHash::sha512_hash_length && insecure_source_encryption_mode == 0) {
|
||||
for (int i = EncryptionModeSHA512; i <= EncryptionModeSHA512Triple; ++i) {
|
||||
if (i != encryption_mode &&
|
||||
eqcrypt_verify_hash(account_username, account_password, password_hash, i)) {
|
||||
insecure_source_encryption_mode = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (encryption_mode < EncryptionModeArgon2) {
|
||||
encryption_mode = EncryptionModeArgon2;
|
||||
}
|
||||
|
||||
if (insecure_source_encryption_mode > 0) {
|
||||
LogInfo(
|
||||
"[{}] Updated insecure password user [{}] loginserver [{}] from mode [{}] ({}) to mode [{}] ({})",
|
||||
__func__,
|
||||
account_username,
|
||||
source_loginserver,
|
||||
GetEncryptionByModeId(insecure_source_encryption_mode),
|
||||
insecure_source_encryption_mode,
|
||||
GetEncryptionByModeId(encryption_mode),
|
||||
encryption_mode
|
||||
);
|
||||
uint32 insecure_source_encryption_mode = 0;
|
||||
|
||||
server.db->UpdateLoginserverAccountPasswordHash(
|
||||
account_username,
|
||||
source_loginserver,
|
||||
eqcrypt_hash(
|
||||
account_username,
|
||||
account_password,
|
||||
encryption_mode
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
auto verify_encryption_mode = [&](int start, int end) {
|
||||
for (int i = start; i <= end; ++i) {
|
||||
if (i != encryption_mode && eqcrypt_verify_hash(a.account_name, c.password, a.account_password, i)) {
|
||||
insecure_source_encryption_mode = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (a.account_password.length()) {
|
||||
case CryptoHash::md5_hash_length:
|
||||
verify_encryption_mode(EncryptionModeMD5, EncryptionModeMD5Triple);
|
||||
break;
|
||||
case CryptoHash::sha1_hash_length:
|
||||
if (insecure_source_encryption_mode == 0) {
|
||||
verify_encryption_mode(EncryptionModeSHA, EncryptionModeSHATriple);
|
||||
}
|
||||
break;
|
||||
case CryptoHash::sha512_hash_length:
|
||||
if (insecure_source_encryption_mode == 0) {
|
||||
verify_encryption_mode(EncryptionModeSHA512, EncryptionModeSHA512Triple);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (insecure_source_encryption_mode > 0) {
|
||||
LogInfo(
|
||||
"Updated insecure password user [{}] loginserver [{}] from mode [{}] ({}) to mode [{}] ({})",
|
||||
c.username,
|
||||
c.source_loginserver,
|
||||
GetEncryptionByModeId(insecure_source_encryption_mode),
|
||||
insecure_source_encryption_mode,
|
||||
GetEncryptionByModeId(encryption_mode),
|
||||
encryption_mode
|
||||
);
|
||||
|
||||
LoginAccountsRepository::UpdateAccountPassword(database, a, c.password);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_account_name
|
||||
* @param db_account_id
|
||||
* @param db_loginserver
|
||||
*/
|
||||
void Client::DoSuccessfulLogin(
|
||||
const std::string& in_account_name,
|
||||
int db_account_id,
|
||||
const std::string &db_loginserver
|
||||
)
|
||||
void Client::DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts &a)
|
||||
{
|
||||
m_stored_user.clear();
|
||||
m_stored_pass.clear();
|
||||
m_stored_username.clear();
|
||||
m_stored_password.clear();
|
||||
|
||||
server.client_manager->RemoveExistingClient(db_account_id, db_loginserver);
|
||||
LogInfo(
|
||||
"Successful login for user id [{}] account name [{}] login server [{}]",
|
||||
a.id,
|
||||
a.account_name,
|
||||
a.source_loginserver
|
||||
);
|
||||
|
||||
server.client_manager->RemoveExistingClient(a.id, a.source_loginserver);
|
||||
|
||||
in_addr in{};
|
||||
in.s_addr = m_connection->GetRemoteIP();
|
||||
|
||||
server.db->UpdateLSAccountData(db_account_id, std::string(inet_ntoa(in)));
|
||||
GenerateKey();
|
||||
a.last_ip_address = std::string(inet_ntoa(in));
|
||||
LoginAccountsRepository::UpdateOne(database, a);
|
||||
|
||||
m_account_id = db_account_id;
|
||||
m_account_name = in_account_name;
|
||||
m_loginserver_name = db_loginserver;
|
||||
GenerateRandomLoginKey();
|
||||
|
||||
m_account_id = a.id;
|
||||
m_account_name = a.account_name;
|
||||
m_loginserver_name = a.source_loginserver;
|
||||
|
||||
// unencrypted
|
||||
LoginBaseMessage_Struct base_header{};
|
||||
base_header.sequence = m_llrs.sequence;
|
||||
base_header.compressed = false;
|
||||
base_header.encrypt_type = m_llrs.encrypt_type;
|
||||
base_header.unk3 = m_llrs.unk3;
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.compressed = false;
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
|
||||
// not serializing any of the variable length strings so just use struct directly
|
||||
PlayerLoginReply_Struct login_reply{};
|
||||
login_reply.base_reply.success = true;
|
||||
login_reply.base_reply.error_str_id = 101; // No Error
|
||||
login_reply.unk1 = 0;
|
||||
login_reply.unk2 = 0;
|
||||
login_reply.lsid = db_account_id;
|
||||
login_reply.failed_attempts = 0;
|
||||
login_reply.show_player_count = server.options.IsShowPlayerCountEnabled();
|
||||
login_reply.offer_min_days = 99;
|
||||
login_reply.offer_min_views = -1;
|
||||
login_reply.offer_cooldown_minutes = 0;
|
||||
login_reply.web_offer_number = 0;
|
||||
login_reply.web_offer_min_days = 99;
|
||||
login_reply.web_offer_min_views = -1;
|
||||
login_reply.web_offer_cooldown_minutes = 0;
|
||||
memcpy(login_reply.key, m_key.c_str(), m_key.size());
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = true;
|
||||
r.base_reply.error_str_id = 101; // No Error
|
||||
r.unk1 = 0;
|
||||
r.unk2 = 0;
|
||||
r.lsid = a.id;
|
||||
r.failed_attempts = 0;
|
||||
r.show_player_count = server.options.IsShowPlayerCountEnabled();
|
||||
r.offer_min_days = 99;
|
||||
r.offer_min_views = -1;
|
||||
r.offer_cooldown_minutes = 0;
|
||||
r.web_offer_number = 0;
|
||||
r.web_offer_min_days = 99;
|
||||
r.web_offer_min_views = -1;
|
||||
r.web_offer_cooldown_minutes = 0;
|
||||
memcpy(r.key, m_key.c_str(), m_key.size());
|
||||
|
||||
SendExpansionPacketData(login_reply);
|
||||
SendExpansionPacketData(r);
|
||||
|
||||
char encrypted_buffer[80] = {0};
|
||||
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
|
||||
|
||||
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
outapp->WriteData(&base_header, sizeof(base_header));
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
outapp->WriteData(&h, sizeof(h));
|
||||
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(outapp.get());
|
||||
@ -569,19 +490,21 @@ void Client::DoSuccessfulLogin(
|
||||
m_client_status = cs_logged_in;
|
||||
}
|
||||
|
||||
void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
|
||||
void Client::SendExpansionPacketData(PlayerLoginReply &plrs)
|
||||
{
|
||||
SerializeBuffer buf;
|
||||
//from eqlsstr_us.txt id of each expansion, excluding 'Everquest'
|
||||
int ExpansionLookup[20] = { 3007, 3008, 3009, 3010, 3012,
|
||||
3014, 3031, 3033, 3036, 3040,
|
||||
3045, 3046, 3047, 3514, 3516,
|
||||
3518, 3520, 3522, 3524 };
|
||||
|
||||
int ExpansionLookup[20] = {
|
||||
3007, 3008, 3009, 3010, 3012,
|
||||
3014, 3031, 3033, 3036, 3040,
|
||||
3045, 3046, 3047, 3514, 3516,
|
||||
3518, 3520, 3522, 3524
|
||||
};
|
||||
|
||||
if (server.options.IsDisplayExpansions()) {
|
||||
|
||||
int32_t expansion = server.options.GetMaxExpansions();
|
||||
int32_t expansion = server.options.GetMaxExpansions();
|
||||
int32_t owned_expansion = (expansion << 1) | 1;
|
||||
|
||||
if (m_client_version == cv_sod) {
|
||||
@ -593,15 +516,14 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
|
||||
buf.WriteInt32(19); //number of expansions to include in packet
|
||||
|
||||
//generate expansion data
|
||||
for (int i = 0; i < 19; i++)
|
||||
{
|
||||
buf.WriteInt32(i); //sequenctial number
|
||||
buf.WriteInt32((expansion & (1 << i)) == (1 << i) ? 0x01 : 0x00); //1 own 0 not own
|
||||
for (int i = 0; i < 19; i++) {
|
||||
buf.WriteInt32(i); //sequenctial number
|
||||
buf.WriteInt32((expansion & (1 << i)) == (1 << i) ? 0x01 : 0x00); //1 own 0 not own
|
||||
buf.WriteInt8(0x00);
|
||||
buf.WriteInt32(ExpansionLookup[i]); //from eqlsstr_us.txt
|
||||
buf.WriteInt32(0x179E); //from eqlsstr_us.txt for buttons/order
|
||||
buf.WriteInt32(0xFFFFFFFF); //end identification
|
||||
buf.WriteInt8(0x0); //force order window to appear 1 appear 0 not appear
|
||||
buf.WriteInt32(ExpansionLookup[i]); //from eqlsstr_us.txt
|
||||
buf.WriteInt32(0x179E); //from eqlsstr_us.txt for buttons/order
|
||||
buf.WriteInt32(0xFFFFFFFF); //end identification
|
||||
buf.WriteInt8(0x0); //force order window to appear 1 appear 0 not appear
|
||||
buf.WriteInt8(0x0);
|
||||
buf.WriteInt32(0x0000);
|
||||
buf.WriteInt32(0x0000);
|
||||
@ -612,79 +534,21 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
|
||||
m_connection->QueuePacket(out.get());
|
||||
|
||||
}
|
||||
else if (m_client_version == cv_titanium)
|
||||
{
|
||||
if (expansion >= EQ::expansions::bitPoR)
|
||||
{
|
||||
else if (m_client_version == cv_titanium) {
|
||||
if (expansion >= EQ::expansions::bitPoR) {
|
||||
// Titanium shipped with 10 expansions. Set owned expansions to be max 10.
|
||||
plrs.offer_min_days = ((EQ::expansions::bitDoD << 2) | 1) - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
plrs.offer_min_days = owned_expansion;
|
||||
}
|
||||
// Titanium shipped with 10 expansions. Set owned expansions to be max 10.
|
||||
plrs.web_offer_min_views = ((EQ::expansions::bitDoD << 2) | 1) - 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
void Client::CreateLocalAccount(const std::string &username, const std::string &password)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
auto hash = eqcrypt_hash(username, password, mode);
|
||||
unsigned int db_id = 0;
|
||||
if (!server.db->CreateLoginData(username, hash, "local", db_id)) {
|
||||
DoFailedLogin();
|
||||
}
|
||||
else {
|
||||
DoSuccessfulLogin(username, db_id, "local");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_account_name
|
||||
* @param in_account_password
|
||||
* @param loginserver_account_id
|
||||
*/
|
||||
void Client::CreateEQEmuAccount(
|
||||
const std::string &in_account_name,
|
||||
const std::string &in_account_password,
|
||||
unsigned int loginserver_account_id
|
||||
)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
auto hash = eqcrypt_hash(in_account_name, in_account_password, mode);
|
||||
|
||||
if (server.db->DoesLoginServerAccountExist(in_account_name, hash, "eqemu", loginserver_account_id)) {
|
||||
DoSuccessfulLogin(in_account_name, loginserver_account_id, "eqemu");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.db->CreateLoginDataWithID(in_account_name, hash, "eqemu", loginserver_account_id)) {
|
||||
DoFailedLogin();
|
||||
}
|
||||
else {
|
||||
DoSuccessfulLogin(in_account_name, loginserver_account_id, "eqemu");
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::ProcessHealthCheck(std::string username)
|
||||
{
|
||||
if (username == "healthcheckuser") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Client::GetClientDescription()
|
||||
std::string Client::GetClientLoggingDescription()
|
||||
{
|
||||
in_addr in{};
|
||||
in.s_addr = GetConnection()->GetRemoteIP();
|
||||
|
||||
@ -8,204 +8,60 @@
|
||||
#include "../common/net/dns.h"
|
||||
#include "../common/net/daybreak_connection.h"
|
||||
#include "login_types.h"
|
||||
#include "../common/repositories/login_accounts_repository.h"
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* Client class, controls a single client and it's connection to the login server
|
||||
*/
|
||||
class Client {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor, sets our connection to c and version to v
|
||||
*
|
||||
* @param c
|
||||
* @param v
|
||||
*/
|
||||
Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Client() {}
|
||||
|
||||
/**
|
||||
* Processes the client's connection and does various actions
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
bool Process();
|
||||
void HandleSessionReady(const char *data, unsigned int size);
|
||||
void HandleLogin(const char *data, unsigned int size);
|
||||
|
||||
/**
|
||||
* Sends our reply to session ready packet
|
||||
*
|
||||
* @param data
|
||||
* @param size
|
||||
*/
|
||||
void Handle_SessionReady(const char *data, unsigned int size);
|
||||
|
||||
/**
|
||||
* Verifies login and send a reply
|
||||
*
|
||||
* @param data
|
||||
* @param size
|
||||
*/
|
||||
void Handle_Login(const char *data, unsigned int size);
|
||||
|
||||
/**
|
||||
* Sends the expansion data packet
|
||||
*
|
||||
* Titanium uses the encrypted data block to contact the expansion (You own xxx:) and the max expansions (of yyy)
|
||||
* Rof uses a seperate data packet specifically for the expansion data
|
||||
* Live, as of July 2021 uses a similar but slightly different seperate data packet
|
||||
*
|
||||
* @param PlayerLoginReply_Struct
|
||||
*
|
||||
*/
|
||||
void SendExpansionPacketData(PlayerLoginReply_Struct& plrs);
|
||||
|
||||
/**
|
||||
* Sends a packet to the requested server to see if the client is allowed or not
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void Handle_Play(const char *data);
|
||||
|
||||
/**
|
||||
* Sends a server list packet to the client
|
||||
*
|
||||
* @param seq
|
||||
*/
|
||||
// Sends the expansion data packet
|
||||
// Titanium uses the encrypted data block to contact the expansion (You own xxx:) and the max expansions (of yyy)
|
||||
// Rof uses a separate data packet specifically for the expansion data
|
||||
// Live, as of July 2021 uses a similar but slightly different seperate data packet
|
||||
void SendExpansionPacketData(PlayerLoginReply &plrs);
|
||||
void SendPlayToWorld(const char *data);
|
||||
void SendServerListPacket(uint32 seq);
|
||||
|
||||
/**
|
||||
* Sends the input packet to the client and clears our play response states
|
||||
*
|
||||
* @param outapp
|
||||
*/
|
||||
void SendPlayResponse(EQApplicationPacket *outapp);
|
||||
|
||||
/**
|
||||
* Generates a random login key for the client during login
|
||||
*/
|
||||
void GenerateKey();
|
||||
|
||||
/**
|
||||
* Gets the account id of this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
void GenerateRandomLoginKey();
|
||||
unsigned int GetAccountID() const { return m_account_id; }
|
||||
|
||||
/**
|
||||
* Gets the loginserver name of this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetLoginServerName() const { return m_loginserver_name; }
|
||||
|
||||
/**
|
||||
* Gets the account name of this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetAccountName() const { return m_account_name; }
|
||||
|
||||
/**
|
||||
* Returns a description for the client for logging
|
||||
* @return std::string
|
||||
*/
|
||||
std::string GetClientDescription();
|
||||
|
||||
/**
|
||||
* Gets the key generated at login for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetKey() const { return m_key; }
|
||||
|
||||
/**
|
||||
* Gets the server selected to be played on for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetPlayServerID() const { return m_play_server_id; }
|
||||
|
||||
/**
|
||||
* Gets the play sequence state for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
|
||||
|
||||
/**
|
||||
* Gets the client version
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetClientLoggingDescription();
|
||||
std::string GetLoginKey() const { return m_key; }
|
||||
unsigned int GetSelectedPlayServerID() const { return m_selected_play_server_id; }
|
||||
unsigned int GetCurrentPlaySequence() const { return m_play_sequence_id; }
|
||||
LSClientVersion GetClientVersion() const { return m_client_version; }
|
||||
|
||||
/**
|
||||
* Gets the connection for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<EQStreamInterface> GetConnection() { return m_connection; }
|
||||
|
||||
/**
|
||||
* Attempts to create a login account
|
||||
*
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param loginserver
|
||||
*/
|
||||
void AttemptLoginAccountCreation(const std::string &user, const std::string &pass, const std::string &loginserver);
|
||||
|
||||
/**
|
||||
* Does a failed login
|
||||
*/
|
||||
void DoFailedLogin();
|
||||
|
||||
/**
|
||||
* Verifies a login hash, will also attempt to update a login hash if needed
|
||||
*
|
||||
* @param account_username
|
||||
* @param source_loginserver
|
||||
* @param account_password
|
||||
* @param password_hash
|
||||
* @return
|
||||
*/
|
||||
bool VerifyLoginHash(
|
||||
const std::string &account_username,
|
||||
const std::string &source_loginserver,
|
||||
const std::string &account_password,
|
||||
const std::string &password_hash
|
||||
);
|
||||
|
||||
void DoSuccessfulLogin(const std::string& in_account_name, int db_account_id, const std::string &db_loginserver);
|
||||
void CreateLocalAccount(const std::string &username, const std::string &password);
|
||||
void CreateEQEmuAccount(const std::string &in_account_name, const std::string &in_account_password, unsigned int loginserver_account_id);
|
||||
void AttemptLoginAccountCreation(LoginAccountContext c);
|
||||
void SendFailedLogin();
|
||||
bool VerifyAndUpdateLoginHash(LoginAccountContext c, const LoginAccountsRepository::LoginAccounts& a);
|
||||
void DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts& a);
|
||||
|
||||
private:
|
||||
EQ::Random m_random;
|
||||
std::shared_ptr<EQStreamInterface> m_connection;
|
||||
LSClientVersion m_client_version;
|
||||
LSClientStatus m_client_status;
|
||||
|
||||
std::string m_account_name;
|
||||
unsigned int m_account_id;
|
||||
std::string m_loginserver_name;
|
||||
unsigned int m_play_server_id;
|
||||
unsigned int m_play_sequence_id;
|
||||
std::string m_key;
|
||||
|
||||
EQ::Random m_random;
|
||||
std::shared_ptr<EQStreamInterface> m_connection;
|
||||
LSClientVersion m_client_version;
|
||||
LSClientStatus m_client_status;
|
||||
std::string m_account_name;
|
||||
unsigned int m_account_id;
|
||||
std::string m_loginserver_name;
|
||||
unsigned int m_selected_play_server_id;
|
||||
unsigned int m_play_sequence_id;
|
||||
std::string m_key;
|
||||
std::unique_ptr<EQ::Net::DaybreakConnectionManager> m_login_connection_manager;
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> m_login_connection;
|
||||
LoginBaseMessage_Struct m_llrs;
|
||||
|
||||
std::string m_stored_user;
|
||||
std::string m_stored_pass;
|
||||
static bool ProcessHealthCheck(std::string username);
|
||||
LoginBaseMessage m_login_base_message;
|
||||
std::string m_stored_username;
|
||||
std::string m_stored_password;
|
||||
static bool ProcessHealthCheck(std::string username) {
|
||||
return username == "healthcheckuser";
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
extern LoginServer server;
|
||||
extern bool run_server;
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/misc.h"
|
||||
#include "../common/path_manager.h"
|
||||
#include "../common/file.h"
|
||||
|
||||
void CheckTitaniumOpcodeFile(const std::string &path) {
|
||||
void CheckTitaniumOpcodeFile(const std::string &path)
|
||||
{
|
||||
if (File::Exists(path)) {
|
||||
return;
|
||||
}
|
||||
@ -32,7 +32,8 @@ void CheckTitaniumOpcodeFile(const std::string &path) {
|
||||
}
|
||||
}
|
||||
|
||||
void CheckSoDOpcodeFile(const std::string& path) {
|
||||
void CheckSoDOpcodeFile(const std::string &path)
|
||||
{
|
||||
if (File::Exists(path)) {
|
||||
return;
|
||||
}
|
||||
@ -56,7 +57,8 @@ void CheckSoDOpcodeFile(const std::string& path) {
|
||||
}
|
||||
}
|
||||
|
||||
void CheckLarionOpcodeFile(const std::string& path) {
|
||||
void CheckLarionOpcodeFile(const std::string &path)
|
||||
{
|
||||
if (File::Exists(path)) {
|
||||
return;
|
||||
}
|
||||
@ -87,8 +89,8 @@ ClientManager::ClientManager()
|
||||
|
||||
EQStreamManagerInterfaceOptions titanium_opts(titanium_port, false, false);
|
||||
|
||||
titanium_stream = new EQ::Net::EQStreamManager(titanium_opts);
|
||||
titanium_ops = new RegularOpcodeManager;
|
||||
m_titanium_stream = new EQ::Net::EQStreamManager(titanium_opts);
|
||||
m_titanium_ops = new RegularOpcodeManager;
|
||||
|
||||
std::string opcodes_path = fmt::format(
|
||||
"{}/{}",
|
||||
@ -98,34 +100,34 @@ ClientManager::ClientManager()
|
||||
|
||||
CheckTitaniumOpcodeFile(opcodes_path);
|
||||
|
||||
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
if (!m_titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
|
||||
"ClientManager fatal error: couldn't load opcodes for Titanium file [{}]",
|
||||
server.config.GetVariableString("client_configuration", "titanium_opcodes", "login_opcodes.conf")
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
titanium_stream->OnNewConnection(
|
||||
m_titanium_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New Titanium client connection from [{0}:{1}]",
|
||||
"New Titanium client connection from [{}:{}]",
|
||||
long2ip(stream->GetRemoteIP()),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&titanium_ops);
|
||||
stream->SetOpcodeManager(&m_titanium_ops);
|
||||
Client *c = new Client(stream, cv_titanium);
|
||||
clients.push_back(c);
|
||||
m_clients.push_back(c);
|
||||
}
|
||||
);
|
||||
|
||||
int sod_port = server.config.GetVariableInt("client_configuration", "sod_port", 5999);
|
||||
|
||||
EQStreamManagerInterfaceOptions sod_opts(sod_port, false, false);
|
||||
sod_stream = new EQ::Net::EQStreamManager(sod_opts);
|
||||
sod_ops = new RegularOpcodeManager;
|
||||
m_sod_stream = new EQ::Net::EQStreamManager(sod_opts);
|
||||
m_sod_ops = new RegularOpcodeManager;
|
||||
|
||||
opcodes_path = fmt::format(
|
||||
"{}/{}",
|
||||
@ -135,26 +137,26 @@ ClientManager::ClientManager()
|
||||
|
||||
CheckSoDOpcodeFile(opcodes_path);
|
||||
|
||||
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
if (!m_sod_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
|
||||
"ClientManager fatal error: couldn't load opcodes for SoD file {}",
|
||||
server.config.GetVariableString("client_configuration", "sod_opcodes", "login_opcodes.conf").c_str()
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
sod_stream->OnNewConnection(
|
||||
m_sod_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New SoD+ client connection from [{0}:{1}]",
|
||||
"New SoD+ client connection from [{}:{}]",
|
||||
long2ip(stream->GetRemoteIP()),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&sod_ops);
|
||||
stream->SetOpcodeManager(&m_sod_ops);
|
||||
auto *c = new Client(stream, cv_sod);
|
||||
clients.push_back(c);
|
||||
m_clients.push_back(c);
|
||||
}
|
||||
);
|
||||
|
||||
@ -162,8 +164,8 @@ ClientManager::ClientManager()
|
||||
|
||||
EQStreamManagerInterfaceOptions larion_opts(larion_port, false, false);
|
||||
|
||||
larion_stream = new EQ::Net::EQStreamManager(larion_opts);
|
||||
larion_ops = new RegularOpcodeManager;
|
||||
m_larion_stream = new EQ::Net::EQStreamManager(larion_opts);
|
||||
m_larion_ops = new RegularOpcodeManager;
|
||||
|
||||
opcodes_path = fmt::format(
|
||||
"{}/{}",
|
||||
@ -173,115 +175,98 @@ ClientManager::ClientManager()
|
||||
|
||||
CheckLarionOpcodeFile(opcodes_path);
|
||||
|
||||
if (!larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
if (!m_larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for Larion file [{0}]",
|
||||
"ClientManager fatal error: couldn't load opcodes for Larion file [{}]",
|
||||
server.config.GetVariableString("client_configuration", "larion_opcodes", "login_opcodes.conf")
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
larion_stream->OnNewConnection(
|
||||
m_larion_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New Larion client connection from [{0}:{1}]",
|
||||
"New Larion client connection from [{}:{}]",
|
||||
long2ip(stream->GetRemoteIP()),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&larion_ops);
|
||||
Client* c = new Client(stream, cv_larion);
|
||||
clients.push_back(c);
|
||||
stream->SetOpcodeManager(&m_larion_ops);
|
||||
Client *c = new Client(stream, cv_larion);
|
||||
m_clients.push_back(c);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ClientManager::~ClientManager()
|
||||
{
|
||||
if (titanium_stream) {
|
||||
delete titanium_stream;
|
||||
}
|
||||
|
||||
if (titanium_ops) {
|
||||
delete titanium_ops;
|
||||
}
|
||||
|
||||
if (sod_stream) {
|
||||
delete sod_stream;
|
||||
}
|
||||
|
||||
if (sod_ops) {
|
||||
delete sod_ops;
|
||||
}
|
||||
ClientManager::~ClientManager() {
|
||||
delete m_titanium_stream;
|
||||
delete m_titanium_ops;
|
||||
delete m_sod_stream;
|
||||
delete m_sod_ops;
|
||||
}
|
||||
|
||||
void ClientManager::Process()
|
||||
{
|
||||
ProcessDisconnect();
|
||||
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->Process() == false) {
|
||||
LogWarning("Client had a fatal error and had to be removed from the login");
|
||||
delete (*iter);
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
m_clients.erase(
|
||||
std::remove_if(
|
||||
m_clients.begin(), m_clients.end(),
|
||||
[](Client *c) {
|
||||
if (!c->Process()) {
|
||||
LogWarning("Client had a fatal error and had to be removed from the login");
|
||||
delete c;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
),
|
||||
m_clients.end());
|
||||
}
|
||||
|
||||
void ClientManager::ProcessDisconnect()
|
||||
{
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end()) {
|
||||
std::shared_ptr<EQStreamInterface> c = (*iter)->GetConnection();
|
||||
if (c->CheckState(CLOSED)) {
|
||||
LogInfo("Client disconnected from the server, removing client");
|
||||
delete (*iter);
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
m_clients.erase(
|
||||
std::remove_if(
|
||||
m_clients.begin(), m_clients.end(),
|
||||
[](Client *c) {
|
||||
if (c->GetConnection()->CheckState(CLOSED)) {
|
||||
LogInfo("Client disconnected from the server, removing client");
|
||||
delete c;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
),
|
||||
m_clients.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
*/
|
||||
void ClientManager::RemoveExistingClient(unsigned int account_id, const std::string &loginserver)
|
||||
{
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->GetAccountID() == account_id && (*iter)->GetLoginServerName().compare(loginserver) == 0) {
|
||||
LogInfo("Client attempting to log in existing client already logged in, removing existing client");
|
||||
delete (*iter);
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
m_clients.erase(
|
||||
std::remove_if(
|
||||
m_clients.begin(), m_clients.end(),
|
||||
[&](Client *c) {
|
||||
if (c->GetAccountID() == account_id && c->GetLoginServerName() == loginserver) {
|
||||
LogInfo("Client attempting to log in existing client already logged in, removing existing client");
|
||||
delete c;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
),
|
||||
m_clients.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
Client *ClientManager::GetClient(unsigned int account_id, const std::string &loginserver)
|
||||
{
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->GetAccountID() == account_id && (*iter)->GetLoginServerName().compare(loginserver) == 0) {
|
||||
return (*iter);
|
||||
auto iter = std::find_if(
|
||||
m_clients.begin(), m_clients.end(),
|
||||
[&](Client *c) {
|
||||
return c->GetAccountID() == account_id && c->GetLoginServerName() == loginserver;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
);
|
||||
|
||||
return nullptr;
|
||||
return (iter != m_clients.end()) ? *iter : nullptr;
|
||||
}
|
||||
|
||||
@ -7,56 +7,23 @@
|
||||
#include "client.h"
|
||||
#include <list>
|
||||
|
||||
/**
|
||||
* Client manager class, holds all the client objects and does basic processing.
|
||||
*/
|
||||
class ClientManager {
|
||||
public:
|
||||
/**
|
||||
* Constructor: sets up the stream factories and opcode managers
|
||||
*/
|
||||
ClientManager();
|
||||
|
||||
/**
|
||||
* Destructor: shuts down the streams and opcode managers
|
||||
*/
|
||||
~ClientManager();
|
||||
|
||||
/**
|
||||
* Processes every client in the internal list, removes them if necessary.
|
||||
*/
|
||||
void Process();
|
||||
|
||||
/**
|
||||
* Removes a client with a certain account id
|
||||
*
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
*/
|
||||
void RemoveExistingClient(unsigned int account_id, const std::string &loginserver);
|
||||
|
||||
/**
|
||||
* Gets a client (if exists) by their account id
|
||||
*
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
Client *GetClient(unsigned int account_id, const std::string &loginserver);
|
||||
void RemoveExistingClient(unsigned int c, const std::string &loginserver);
|
||||
Client *GetClient(unsigned int c, const std::string &loginserver);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Processes disconnected clients, removes them if necessary
|
||||
*/
|
||||
void ProcessDisconnect();
|
||||
|
||||
std::list<Client *> clients;
|
||||
OpcodeManager *titanium_ops;
|
||||
EQ::Net::EQStreamManager *titanium_stream;
|
||||
OpcodeManager *sod_ops;
|
||||
EQ::Net::EQStreamManager *sod_stream;
|
||||
OpcodeManager *larion_ops;
|
||||
EQ::Net::EQStreamManager* larion_stream;
|
||||
std::list<Client *> m_clients;
|
||||
OpcodeManager *m_titanium_ops;
|
||||
EQ::Net::EQStreamManager *m_titanium_stream;
|
||||
OpcodeManager *m_sod_ops;
|
||||
EQ::Net::EQStreamManager *m_sod_stream;
|
||||
OpcodeManager *m_larion_ops;
|
||||
EQ::Net::EQStreamManager *m_larion_stream;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,680 +0,0 @@
|
||||
#include "../common/global_define.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/util/uuid.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
/**
|
||||
* Initial connect
|
||||
*
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param host
|
||||
* @param port
|
||||
* @param name
|
||||
*/
|
||||
Database::Database(
|
||||
std::string user,
|
||||
std::string pass,
|
||||
std::string host,
|
||||
std::string port,
|
||||
std::string name
|
||||
)
|
||||
{
|
||||
uint32 errnum = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!Open(
|
||||
host.c_str(),
|
||||
user.c_str(),
|
||||
pass.c_str(),
|
||||
name.c_str(),
|
||||
Strings::ToUnsignedInt(port),
|
||||
&errnum,
|
||||
errbuf
|
||||
)
|
||||
) {
|
||||
LogError("Failed to connect to database: Error: [{0}]", errbuf);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
LogInfo("Using database [{0}] at [{1}:{2}]", name, host, port);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deconstructor
|
||||
*/
|
||||
Database::~Database()
|
||||
{
|
||||
if (m_database) {
|
||||
mysql_close(m_database);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param password
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::GetLoginDataFromAccountInfo(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
std::string &password,
|
||||
unsigned int &id
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, account_password FROM login_accounts WHERE account_name = '{0}' AND source_loginserver = '{1}' LIMIT 1",
|
||||
Strings::Escape(name),
|
||||
Strings::Escape(loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
LogDebug(
|
||||
"Could not find account for name [{0}] login [{1}]",
|
||||
name,
|
||||
loginserver
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
id = Strings::ToUnsignedInt(row[0]);
|
||||
password = row[1];
|
||||
|
||||
LogDebug(
|
||||
"Found account for name [{0}] login [{1}]",
|
||||
name,
|
||||
loginserver
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @param ip
|
||||
* @param db_account_id
|
||||
* @param db_loginserver
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
bool Database::GetLoginTokenDataFromToken(
|
||||
const std::string &token,
|
||||
const std::string &ip,
|
||||
unsigned int &db_account_id,
|
||||
std::string &db_loginserver,
|
||||
std::string &user
|
||||
)
|
||||
{
|
||||
auto query = fmt::format("SELECT login_server, username, account_id FROM login_tickets WHERE expires > NOW()"
|
||||
" AND id='{0}' AND ip_address='{1}' LIMIT 1",
|
||||
Strings::Escape(token),
|
||||
Strings::Escape(ip));
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.RowCount() == 0 || !results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
db_loginserver = row[0];
|
||||
user = row[1];
|
||||
db_account_id = Strings::ToUnsignedInt(row[2]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
unsigned int Database::GetFreeID(const std::string &loginserver)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT IFNULL(MAX(id), 0) + 1 FROM login_accounts WHERE source_loginserver = '{0}'",
|
||||
Strings::Escape(loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateLoginData(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int &id
|
||||
)
|
||||
{
|
||||
uint32 free_id = GetFreeID(loginserver);
|
||||
id = free_id;
|
||||
|
||||
return CreateLoginDataWithID(name, password, loginserver, free_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
uint32 Database::CreateLoginAccount(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
const std::string &email
|
||||
)
|
||||
{
|
||||
uint32 free_id = GetFreeID(loginserver);
|
||||
|
||||
if (free_id <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
|
||||
"VALUES ({0}, '{1}', '{2}', '{3}', '{4}', NOW(), '127.0.0.1', NOW())",
|
||||
free_id,
|
||||
Strings::Escape(loginserver),
|
||||
Strings::Escape(name),
|
||||
Strings::Escape(password),
|
||||
Strings::Escape(email)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return (results.Success() ? free_id : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_account_name
|
||||
* @param in_account_password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateLoginDataWithID(
|
||||
const std::string &in_account_name,
|
||||
const std::string &in_account_password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
)
|
||||
{
|
||||
if (id == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
|
||||
"VALUES ({0}, '{1}', '{2}', '{3}', 'local_creation', NOW(), '127.0.0.1', NOW())",
|
||||
id,
|
||||
Strings::Escape(loginserver),
|
||||
Strings::Escape(in_account_name),
|
||||
Strings::Escape(in_account_password)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::DoesLoginServerAccountExist(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
)
|
||||
{
|
||||
if (id == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT account_name FROM login_accounts WHERE account_name = '{0}' AND source_loginserver = '{1}'",
|
||||
Strings::Escape(name),
|
||||
Strings::Escape(loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param hash
|
||||
*/
|
||||
void Database::UpdateLoginserverAccountPasswordHash(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
const std::string &hash
|
||||
)
|
||||
{
|
||||
LogDebug(
|
||||
"name [{0}] loginserver [{1}] hash [{2}]",
|
||||
name,
|
||||
loginserver,
|
||||
hash
|
||||
);
|
||||
|
||||
auto query = fmt::format(
|
||||
"UPDATE login_accounts SET account_password = '{0}' WHERE account_name = '{1}' AND source_loginserver = '{2}'",
|
||||
hash,
|
||||
Strings::Escape(name),
|
||||
Strings::Escape(loginserver)
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param short_name
|
||||
* @param long_name
|
||||
* @param login_world_server_admin_id
|
||||
* @return
|
||||
*/
|
||||
Database::DbWorldRegistration Database::GetWorldRegistration(
|
||||
const std::string &short_name,
|
||||
const std::string &long_name,
|
||||
uint32 login_world_server_admin_id
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT\n"
|
||||
" WSR.id,\n"
|
||||
" WSR.tag_description,\n"
|
||||
" WSR.is_server_trusted,\n"
|
||||
" SLT.id,\n"
|
||||
" SLT.description,\n"
|
||||
" ifnull(WSR.login_server_admin_id, 0) AS login_server_admin_id\n"
|
||||
"FROM\n"
|
||||
" login_world_servers AS WSR\n"
|
||||
" JOIN login_server_list_types AS SLT ON WSR.login_server_list_type_id = SLT.id\n"
|
||||
"WHERE\n"
|
||||
" WSR.short_name = '{}' AND WSR.long_name = '{}' AND WSR.login_server_admin_id = {} LIMIT 1",
|
||||
Strings::Escape(short_name),
|
||||
Strings::Escape(long_name),
|
||||
login_world_server_admin_id
|
||||
);
|
||||
|
||||
Database::DbWorldRegistration r{};
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
r.loaded = true;
|
||||
r.server_id = Strings::ToInt(row[0]);
|
||||
r.server_description = row[1];
|
||||
r.server_list_type = Strings::ToInt(row[3]);
|
||||
r.is_server_trusted = Strings::ToInt(row[2]) > 0;
|
||||
r.server_list_description = row[4];
|
||||
r.server_admin_id = Strings::ToUnsignedInt(row[5]);
|
||||
|
||||
if (r.server_admin_id <= 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
auto world_registration_query = fmt::format(
|
||||
"SELECT account_name, account_password FROM login_server_admins WHERE id = {0} LIMIT 1",
|
||||
r.server_admin_id
|
||||
);
|
||||
|
||||
auto world_registration_results = QueryDatabase(world_registration_query);
|
||||
if (world_registration_results.Success() && world_registration_results.RowCount() == 1) {
|
||||
auto world_registration_row = world_registration_results.begin();
|
||||
r.server_admin_account_name = world_registration_row[0];
|
||||
r.server_admin_account_password = world_registration_row[1];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param ip_address
|
||||
*/
|
||||
void Database::UpdateLSAccountData(unsigned int id, std::string ip_address)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"UPDATE login_accounts SET last_ip_address = '{0}', last_login_date = NOW() where id = {1}",
|
||||
ip_address,
|
||||
id
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param password
|
||||
* @param email
|
||||
*/
|
||||
void Database::UpdateLSAccountInfo(
|
||||
unsigned int id,
|
||||
std::string name,
|
||||
std::string password,
|
||||
std::string email
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"REPLACE login_accounts SET id = {0}, account_name = '{1}', account_password = sha('{2}'), "
|
||||
"account_email = '{3}', last_ip_address = '0.0.0.0', last_login_date = now()",
|
||||
id,
|
||||
Strings::Escape(name),
|
||||
Strings::Escape(password),
|
||||
Strings::Escape(email)
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param long_name
|
||||
* @param ip_address
|
||||
*/
|
||||
void Database::UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"UPDATE login_world_servers SET last_login_date = NOW(), last_ip_address = '{0}', long_name = '{1}' WHERE id = {2}",
|
||||
ip_address,
|
||||
Strings::Escape(long_name),
|
||||
id
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param admin_account_password_hash
|
||||
*/
|
||||
bool Database::UpdateLoginWorldAdminAccountPassword(
|
||||
unsigned int id,
|
||||
const std::string &admin_account_password_hash
|
||||
)
|
||||
{
|
||||
auto results = QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE login_server_admins SET account_password = '{}' WHERE id = {}",
|
||||
Strings::Escape(admin_account_password_hash),
|
||||
id
|
||||
)
|
||||
);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param admin_account_username
|
||||
* @param admin_account_password_hash
|
||||
*/
|
||||
bool Database::UpdateLoginWorldAdminAccountPasswordByUsername(
|
||||
const std::string &admin_account_username,
|
||||
const std::string &admin_account_password_hash
|
||||
)
|
||||
{
|
||||
auto results = QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE login_server_admins SET account_password = '{}' WHERE account_name = '{}'",
|
||||
Strings::Escape(admin_account_password_hash),
|
||||
Strings::Escape(admin_account_username)
|
||||
)
|
||||
);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateWorldRegistration(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
std::string server_remote_ip,
|
||||
unsigned int &id,
|
||||
unsigned int &server_admin_id
|
||||
)
|
||||
{
|
||||
auto results = QueryDatabase("SELECT IFNULL(max(id), 0) + 1 FROM login_world_servers");
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
id = Strings::ToUnsignedInt(row[0]);
|
||||
auto insert_query = fmt::format(
|
||||
"INSERT INTO login_world_servers SET id = {0}, long_name = '{1}', short_name = '{2}', last_ip_address = '{3}', \n"
|
||||
"login_server_list_type_id = 3, login_server_admin_id = {4}, is_server_trusted = 0, tag_description = ''",
|
||||
id,
|
||||
Strings::Escape(server_long_name),
|
||||
Strings::Escape(server_short_name),
|
||||
server_remote_ip,
|
||||
server_admin_id
|
||||
);
|
||||
|
||||
auto insert_results = QueryDatabase(insert_query);
|
||||
if (!insert_results.Success()) {
|
||||
LogError(
|
||||
"Failed to register world server {0} - {1}",
|
||||
server_long_name,
|
||||
server_short_name
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param long_name
|
||||
* @param short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
std::string Database::CreateLoginserverApiToken(
|
||||
bool write_mode,
|
||||
bool read_mode
|
||||
)
|
||||
{
|
||||
std::string token = EQ::Util::UUID::Generate().ToString();
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_api_tokens (token, can_write, can_read, created_at) VALUES ('{0}', {1}, {2}, NOW())",
|
||||
token,
|
||||
(write_mode ? "1" : "0"),
|
||||
(read_mode ? "1" : "0")
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param long_name
|
||||
* @param short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
MySQLRequestResult Database::GetLoginserverApiTokens()
|
||||
{
|
||||
return QueryDatabase("SELECT token, can_write, can_read FROM login_api_tokens");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @param account_password
|
||||
* @param first_name
|
||||
* @param last_name
|
||||
* @param email
|
||||
* @param ip_address
|
||||
* @return
|
||||
*/
|
||||
uint32 Database::CreateLoginserverWorldAdminAccount(
|
||||
const std::string &account_name,
|
||||
const std::string &account_password,
|
||||
const std::string &first_name,
|
||||
const std::string &last_name,
|
||||
const std::string &email,
|
||||
const std::string &ip_address
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_server_admins (account_name, account_password, first_name, last_name, email, registration_date, "
|
||||
"registration_ip_address) "
|
||||
"VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', NOW(), '{5}')",
|
||||
Strings::Escape(account_name),
|
||||
Strings::Escape(account_password),
|
||||
Strings::Escape(first_name),
|
||||
Strings::Escape(last_name),
|
||||
Strings::Escape(email),
|
||||
ip_address
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return (results.Success() ? results.LastInsertedID() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
bool Database::DoesLoginserverWorldAdminAccountExist(
|
||||
const std::string &account_name
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT account_name FROM login_server_admins WHERE account_name = '{0}' LIMIT 1",
|
||||
Strings::Escape(account_name)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return (results.RowCount() == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &account_name)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, account_name, account_password, first_name, last_name, email, registration_date, registration_ip_address"
|
||||
" FROM login_server_admins WHERE account_name = '{0}' LIMIT 1",
|
||||
Strings::Escape(account_name)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
Database::DbLoginServerAdmin r{};
|
||||
if (results.RowCount() == 1) {
|
||||
auto row = results.begin();
|
||||
r.loaded = true;
|
||||
r.id = Strings::ToUnsignedInt(row[0]);
|
||||
r.account_name = row[1];
|
||||
r.account_password = row[2];
|
||||
r.first_name = row[3];
|
||||
r.last_name = row[4];
|
||||
r.email = row[5];
|
||||
r.registration_date = row[7];
|
||||
r.registration_ip_address = row[8];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
|
||||
const std::string &account_name,
|
||||
const std::string &source_loginserver
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, account_name, account_password, account_email, source_loginserver, last_ip_address, last_login_date, "
|
||||
"created_at, updated_at"
|
||||
" FROM login_accounts WHERE account_name = '{0}' and source_loginserver = '{1}' LIMIT 1",
|
||||
Strings::Escape(account_name),
|
||||
Strings::Escape(source_loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
Database::DbLoginServerAccount r{};
|
||||
if (results.RowCount() == 1) {
|
||||
auto row = results.begin();
|
||||
r.loaded = true;
|
||||
r.id = Strings::ToUnsignedInt(row[0]);
|
||||
r.account_name = row[1];
|
||||
r.account_password = row[2];
|
||||
r.account_email = row[3];
|
||||
r.source_loginserver = row[4];
|
||||
r.last_ip_address = row[5];
|
||||
r.last_login_date = row[6];
|
||||
r.created_at = row[7];
|
||||
r.updated_at = row[8];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -1,286 +0,0 @@
|
||||
#ifndef EQEMU_DATABASEMYSQL_H
|
||||
#define EQEMU_DATABASEMYSQL_H
|
||||
|
||||
#include "../common/dbcore.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <mysql.h>
|
||||
|
||||
class Database : public DBcore {
|
||||
public:
|
||||
|
||||
Database() { m_database = nullptr; }
|
||||
|
||||
/**
|
||||
* Constructor, tries to set our database to connect to the supplied options.
|
||||
*
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param host
|
||||
* @param port
|
||||
* @param name
|
||||
*/
|
||||
Database(std::string user, std::string pass, std::string host, std::string port, std::string name);
|
||||
|
||||
/**
|
||||
* Destructor, frees our database if needed.
|
||||
*/
|
||||
~Database();
|
||||
|
||||
/**
|
||||
* Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure.
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param password
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool GetLoginDataFromAccountInfo(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
std::string &password,
|
||||
unsigned int &id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @param ip
|
||||
* @param db_account_id
|
||||
* @param db_loginserver
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
bool GetLoginTokenDataFromToken(
|
||||
const std::string &token,
|
||||
const std::string &ip,
|
||||
unsigned int &db_account_id,
|
||||
std::string &db_loginserver,
|
||||
std::string &user
|
||||
);
|
||||
|
||||
/**
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetFreeID(const std::string &loginserver);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool CreateLoginData(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int &id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_name
|
||||
* @param in_account_password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool CreateLoginDataWithID(
|
||||
const std::string &in_account_name,
|
||||
const std::string &in_account_password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param hash
|
||||
*/
|
||||
void UpdateLoginserverAccountPasswordHash(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
const std::string &hash);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool DoesLoginServerAccountExist(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
);
|
||||
|
||||
struct DbWorldRegistration {
|
||||
bool loaded = false;
|
||||
int32 server_id = 0;
|
||||
int8 server_list_type = 3;
|
||||
bool is_server_trusted = false;
|
||||
std::string server_description;
|
||||
std::string server_list_description;
|
||||
std::string server_admin_account_name;
|
||||
std::string server_admin_account_password;
|
||||
uint32 server_admin_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the world registration from the long and short names provided
|
||||
* Needed for world login procedure
|
||||
* Returns true if the record was found, false otherwise
|
||||
*
|
||||
* @param short_name
|
||||
* @param long_name
|
||||
* @param login_world_server_admin_id
|
||||
* @return
|
||||
*/
|
||||
Database::DbWorldRegistration GetWorldRegistration(
|
||||
const std::string &short_name,
|
||||
const std::string &long_name,
|
||||
uint32 login_world_server_admin_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param ip_address
|
||||
*/
|
||||
void UpdateLSAccountData(unsigned int id, std::string ip_address);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param password
|
||||
* @param email
|
||||
*/
|
||||
void UpdateLSAccountInfo(unsigned int id, std::string name, std::string password, std::string email);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param long_name
|
||||
* @param ip_address
|
||||
*/
|
||||
void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
||||
|
||||
/**
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool CreateWorldRegistration(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
std::string server_remote_ip,
|
||||
unsigned int &id,
|
||||
unsigned int &server_admin_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param write_mode
|
||||
* @param read_mode
|
||||
* @return
|
||||
*/
|
||||
std::string CreateLoginserverApiToken(bool write_mode, bool read_mode);
|
||||
MySQLRequestResult GetLoginserverApiTokens();
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @param account_password
|
||||
* @param first_name
|
||||
* @param last_name
|
||||
* @param email
|
||||
* @param ip_address
|
||||
* @return
|
||||
*/
|
||||
uint32 CreateLoginserverWorldAdminAccount(
|
||||
const std::string &account_name,
|
||||
const std::string &account_password,
|
||||
const std::string &first_name,
|
||||
const std::string &last_name,
|
||||
const std::string &email,
|
||||
const std::string &ip_address
|
||||
);
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
bool DoesLoginserverWorldAdminAccountExist(const std::string &account_name);
|
||||
|
||||
struct DbLoginServerAdmin {
|
||||
bool loaded = false;
|
||||
uint32 id;
|
||||
std::string account_name;
|
||||
std::string account_password;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::string email;
|
||||
std::string registration_date;
|
||||
std::string registration_ip_address;
|
||||
};
|
||||
|
||||
Database::DbLoginServerAdmin GetLoginServerAdmin(const std::string &account_name);
|
||||
|
||||
struct DbLoginServerAccount {
|
||||
bool loaded = false;
|
||||
uint32 id;
|
||||
std::string account_name;
|
||||
std::string account_password;
|
||||
std::string account_email;
|
||||
std::string source_loginserver;
|
||||
std::string last_login_date;
|
||||
std::string last_ip_address;
|
||||
std::string created_at;
|
||||
std::string updated_at;
|
||||
};
|
||||
|
||||
Database::DbLoginServerAccount GetLoginServerAccountByAccountName(
|
||||
const std::string &account_name,
|
||||
const std::string &source_loginserver = "local"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param admin_account_password_hash
|
||||
*/
|
||||
bool UpdateLoginWorldAdminAccountPassword(
|
||||
unsigned int id,
|
||||
const std::string& admin_account_password_hash
|
||||
);
|
||||
|
||||
/**
|
||||
* @param admin_account_username
|
||||
* @param admin_account_password_hash
|
||||
*/
|
||||
bool UpdateLoginWorldAdminAccountPasswordByUsername(
|
||||
const std::string &admin_account_username,
|
||||
const std::string &admin_account_password_hash
|
||||
);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
uint32 CreateLoginAccount(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver = "local",
|
||||
const std::string &email = "local_creation"
|
||||
);
|
||||
|
||||
protected:
|
||||
MYSQL *m_database{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -21,10 +21,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param mode
|
||||
* @return
|
||||
*/
|
||||
std::string GetEncryptionByModeId(uint32 mode)
|
||||
{
|
||||
switch (mode) {
|
||||
@ -61,13 +57,6 @@ std::string GetEncryptionByModeId(uint32 mode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buffer_in
|
||||
* @param buffer_in_sz
|
||||
* @param buffer_out
|
||||
* @param enc
|
||||
* @return
|
||||
*/
|
||||
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc)
|
||||
{
|
||||
#ifdef EQEMU_USE_MBEDTLS
|
||||
@ -113,7 +102,7 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
|
||||
unsigned char iv[8];
|
||||
memset(&key, 0, MBEDTLS_DES_KEY_SIZE);
|
||||
memset(&iv, 0, 8);
|
||||
|
||||
|
||||
mbedtls_des_context context;
|
||||
mbedtls_des_setkey_dec(&context, key);
|
||||
mbedtls_des_crypt_cbc(&context, MBEDTLS_DES_DECRYPT, buffer_in_sz, iv, (const unsigned char*)buffer_in, (unsigned char*)buffer_out);
|
||||
@ -123,23 +112,19 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
DES_key_schedule k;
|
||||
DES_cblock v;
|
||||
|
||||
|
||||
memset(&k, 0, sizeof(DES_key_schedule));
|
||||
memset(&v, 0, sizeof(DES_cblock));
|
||||
|
||||
|
||||
if (!enc && buffer_in_sz && buffer_in_sz % 8 != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
DES_ncbc_encrypt((const unsigned char*)buffer_in, (unsigned char*)buffer_out, (long)buffer_in_sz, &k, &v, enc);
|
||||
#endif
|
||||
return buffer_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
std::string eqcrypt_md5(const std::string &msg)
|
||||
{
|
||||
std::string ret;
|
||||
@ -174,10 +159,6 @@ std::string eqcrypt_md5(const std::string &msg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
std::string eqcrypt_sha1(const std::string &msg)
|
||||
{
|
||||
std::string ret;
|
||||
@ -212,10 +193,6 @@ std::string eqcrypt_sha1(const std::string &msg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
std::string eqcrypt_sha512(const std::string &msg)
|
||||
{
|
||||
std::string ret;
|
||||
@ -252,10 +229,6 @@ std::string eqcrypt_sha512(const std::string &msg)
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
std::string eqcrypt_argon2(const std::string &msg)
|
||||
{
|
||||
char buffer[crypto_pwhash_STRBYTES] = {0};
|
||||
@ -275,10 +248,6 @@ std::string eqcrypt_argon2(const std::string &msg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
std::string eqcrypt_scrypt(const std::string &msg)
|
||||
{
|
||||
char buffer[crypto_pwhash_scryptsalsa208sha256_STRBYTES] = {0};
|
||||
@ -300,12 +269,6 @@ std::string eqcrypt_scrypt(const std::string &msg)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param mode
|
||||
* @return
|
||||
*/
|
||||
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
@ -346,13 +309,6 @@ std::string eqcrypt_hash(const std::string &username, const std::string &passwor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param pwhash
|
||||
* @param mode
|
||||
* @return
|
||||
*/
|
||||
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
#include <string>
|
||||
#include "../common/types.h"
|
||||
#include "login_types.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/strings.h"
|
||||
|
||||
enum EncryptionMode {
|
||||
EncryptionModeMD5 = 1,
|
||||
@ -26,11 +29,34 @@ namespace CryptoHash {
|
||||
const int sha512_hash_length = 128;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mode
|
||||
* @return
|
||||
*/
|
||||
std::string GetEncryptionByModeId(uint32 mode);
|
||||
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc);
|
||||
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
|
||||
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);
|
||||
|
||||
struct EncryptionResult {
|
||||
std::string password;
|
||||
int mode = 0;
|
||||
std::string mode_name;
|
||||
};
|
||||
|
||||
static EncryptionResult EncryptPasswordFromContext(LoginAccountContext c, int mode = EncryptionModeSCrypt)
|
||||
{
|
||||
if (mode == 0) {
|
||||
LogError("Encryption mode not set!");
|
||||
return {};
|
||||
}
|
||||
|
||||
EncryptionResult r;
|
||||
r.password = eqcrypt_hash(
|
||||
c.username,
|
||||
c.password,
|
||||
mode
|
||||
);
|
||||
r.mode = mode;
|
||||
r.mode_name = GetEncryptionByModeId(r.mode);
|
||||
|
||||
LogInfo("Encrypted password for user [{}] using mode [{}] ({})", c.username, r.mode_name, r.mode);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -3,29 +3,24 @@
|
||||
|
||||
#include <utility>
|
||||
#include "../common/json_config.h"
|
||||
#include "database.h"
|
||||
#include "encryption.h"
|
||||
#include "options.h"
|
||||
#include "server_manager.h"
|
||||
#include "world_server_manager.h"
|
||||
#include "client_manager.h"
|
||||
#include "loginserver_webserver.h"
|
||||
|
||||
/**
|
||||
* Login server struct, Contains every variable for the server that needs to exist outside the scope of main()
|
||||
*/
|
||||
struct LoginServer
|
||||
{
|
||||
struct LoginServer {
|
||||
public:
|
||||
|
||||
LoginServer() : db(nullptr), server_manager(nullptr) {
|
||||
LoginServer() : server_manager(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EQ::JsonConfigFile config;
|
||||
Database *db;
|
||||
LoginserverWebserver::TokenManager *token_manager{};
|
||||
Options options;
|
||||
ServerManager *server_manager;
|
||||
WorldServerManager *server_manager;
|
||||
ClientManager *client_manager{};
|
||||
};
|
||||
|
||||
|
||||
@ -4,30 +4,30 @@
|
||||
#pragma pack(1)
|
||||
|
||||
// unencrypted base message header in all packets
|
||||
struct LoginBaseMessage_Struct {
|
||||
struct LoginBaseMessage {
|
||||
int32_t sequence; // request type/login sequence (2: handshake, 3: login, 4: serverlist, ...)
|
||||
bool compressed; // true: deflated
|
||||
int8_t encrypt_type; // 1: invert (unused) 2: des (2 for encrypted player logins and order expansions) (client uses what it sent, ignores in reply)
|
||||
int32_t unk3; // unused?
|
||||
};
|
||||
|
||||
struct LoginBaseReplyMessage_Struct {
|
||||
struct LoginBaseReplyMessage {
|
||||
bool success; // 0: failure (shows error string) 1: success
|
||||
int32_t error_str_id; // last error eqlsstr id, default: 101 (no error)
|
||||
char str[1]; // variable length, unknown (may be unused, this struct is a common pattern elsewhere)
|
||||
};
|
||||
|
||||
struct LoginHandShakeReply_Struct {
|
||||
LoginBaseMessage_Struct base_header;
|
||||
LoginBaseReplyMessage_Struct base_reply;
|
||||
char unknown[1]; // variable length string
|
||||
struct LoginHandShakeReply {
|
||||
LoginBaseMessage base_header;
|
||||
LoginBaseReplyMessage base_reply;
|
||||
char unknown[1]; // variable length string
|
||||
};
|
||||
|
||||
// variable length, can use directly if not serializing strings
|
||||
struct PlayerLoginReply_Struct {
|
||||
struct PlayerLoginReply {
|
||||
// base header excluded to make struct data easier to encrypt
|
||||
//LoginBaseMessage_Struct base_header;
|
||||
LoginBaseReplyMessage_Struct base_reply;
|
||||
//LoginBaseMessage base_header;
|
||||
LoginBaseReplyMessage base_reply;
|
||||
|
||||
int8_t unk1; // (default: 0)
|
||||
int8_t unk2; // (default: 0)
|
||||
@ -47,7 +47,7 @@ struct PlayerLoginReply_Struct {
|
||||
};
|
||||
|
||||
// variable length, for reference
|
||||
struct LoginClientServerData_Struct {
|
||||
struct LoginClientServerData {
|
||||
char ip[1];
|
||||
int32_t server_type; // legends, preferred, standard
|
||||
int32_t server_id;
|
||||
@ -59,24 +59,24 @@ struct LoginClientServerData_Struct {
|
||||
};
|
||||
|
||||
// variable length, for reference
|
||||
struct ServerListReply_Struct {
|
||||
LoginBaseMessage_Struct base_header;
|
||||
LoginBaseReplyMessage_Struct base_reply;
|
||||
struct ServerListReply {
|
||||
LoginBaseMessage base_header;
|
||||
LoginBaseReplyMessage base_reply;
|
||||
|
||||
int32_t server_count;
|
||||
LoginClientServerData_Struct servers[0];
|
||||
int32_t server_count;
|
||||
LoginClientServerData servers[0];
|
||||
};
|
||||
|
||||
struct PlayEverquestRequest_Struct {
|
||||
LoginBaseMessage_Struct base_header;
|
||||
uint32 server_number;
|
||||
struct PlayEverquestRequest {
|
||||
LoginBaseMessage base_header;
|
||||
uint32 server_number;
|
||||
};
|
||||
|
||||
// SCJoinServerReply
|
||||
struct PlayEverquestResponse_Struct {
|
||||
LoginBaseMessage_Struct base_header;
|
||||
LoginBaseReplyMessage_Struct base_reply;
|
||||
uint32 server_number;
|
||||
struct PlayEverquestResponse {
|
||||
LoginBaseMessage base_header;
|
||||
LoginBaseReplyMessage base_reply;
|
||||
uint32 server_number;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
@ -95,6 +95,34 @@ enum LSClientStatus {
|
||||
cs_logged_in
|
||||
};
|
||||
|
||||
struct LoginWorldContext {
|
||||
std::string long_name;
|
||||
std::string short_name;
|
||||
std::string password;
|
||||
std::string password_hash;
|
||||
int64 admin_id = 0;
|
||||
};
|
||||
|
||||
struct LoginWorldAdminAccountContext {
|
||||
int64 id;
|
||||
std::string username;
|
||||
std::string password;
|
||||
std::string password_hash;
|
||||
std::string email;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::string ip_address;
|
||||
};
|
||||
|
||||
struct LoginAccountContext {
|
||||
std::string username;
|
||||
std::string password;
|
||||
std::string email;
|
||||
std::string source_loginserver = "local";
|
||||
uint32 login_account_id = 0;
|
||||
bool password_is_encrypted = false;
|
||||
};
|
||||
|
||||
namespace LS {
|
||||
namespace ServerStatusFlags {
|
||||
enum eServerStatusFlags {
|
||||
@ -123,13 +151,13 @@ namespace LS {
|
||||
};
|
||||
|
||||
namespace ErrStr {
|
||||
constexpr static int ERROR_NONE = 101; // No Error
|
||||
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
|
||||
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
|
||||
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
|
||||
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
|
||||
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
|
||||
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
|
||||
constexpr static int ERROR_NONE = 101; // No Error
|
||||
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
|
||||
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
|
||||
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
|
||||
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
|
||||
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
|
||||
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -33,10 +33,6 @@ CREATE TABLE `login_server_list_types` (
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
INSERT INTO `login_server_list_types` (`id`, `description`) VALUES ('1', 'Legends'),
|
||||
('2', 'Preferred'),
|
||||
('3', 'Standard');
|
||||
|
||||
DROP TABLE IF EXISTS `login_world_servers`;
|
||||
CREATE TABLE `login_world_servers` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
|
||||
@ -5,15 +5,11 @@
|
||||
#include "login_server.h"
|
||||
#include "loginserver_webserver.h"
|
||||
#include "account_management.h"
|
||||
#include "../common/repositories/login_api_tokens_repository.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
namespace LoginserverCommandHandler {
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void CommandHandler(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1) { return; }
|
||||
@ -22,14 +18,7 @@ namespace LoginserverCommandHandler {
|
||||
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
|
||||
EQEmuCommand::DisplayDebug(cmd);
|
||||
|
||||
/**
|
||||
* Declare command mapping
|
||||
*/
|
||||
auto function_map = EQEmuCommand::function_map;
|
||||
|
||||
/**
|
||||
* Register commands
|
||||
*/
|
||||
function_map["login-user:check-credentials"] = &LoginserverCommandHandler::CheckLoginserverUserCredentials;
|
||||
function_map["login-user:check-external-credentials"] = &LoginserverCommandHandler::CheckExternalLoginserverUserCredentials;
|
||||
function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
|
||||
@ -43,12 +32,6 @@ namespace LoginserverCommandHandler {
|
||||
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Creates Loginserver API Token";
|
||||
@ -69,22 +52,22 @@ namespace LoginserverCommandHandler {
|
||||
bool can_write = cmd[{"-w", "--write"}];
|
||||
|
||||
if (!can_read || !can_write) {
|
||||
LogInfo("[{0}] --read or --write must be set or both!", __func__);
|
||||
LogInfo("--read or --write must be set or both!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string token = server.db->CreateLoginserverApiToken(can_write, can_read);
|
||||
if (!token.empty()) {
|
||||
LogInfo("[{0}] Created Loginserver API token [{1}]", __func__, token);
|
||||
auto t = LoginApiTokensRepository::NewEntity();
|
||||
t.can_read = can_read;
|
||||
t.can_write = can_write;
|
||||
t.token = EQ::Util::UUID::Generate().ToString();
|
||||
t.created_at = std::time(nullptr);
|
||||
|
||||
auto created = LoginApiTokensRepository::InsertOne(database, t);
|
||||
if (created.id) {
|
||||
LogInfo("Created Loginserver API token [{}] [{}]", created.id, created.token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Lists Loginserver API Tokens";
|
||||
@ -96,9 +79,10 @@ namespace LoginserverCommandHandler {
|
||||
server.token_manager = new LoginserverWebserver::TokenManager;
|
||||
server.token_manager->LoadApiTokens();
|
||||
|
||||
for (auto &it : server.token_manager->loaded_api_tokens) {
|
||||
for (auto &it: server.token_manager->loaded_api_tokens) {
|
||||
LogInfo(
|
||||
"token [{0}] can_write [{1}] can_read [{2}]",
|
||||
"token id [{}] [{}] can_write [{}] can_read [{}]",
|
||||
it.second.id,
|
||||
it.second.token,
|
||||
it.second.can_write,
|
||||
it.second.can_read
|
||||
@ -106,12 +90,6 @@ namespace LoginserverCommandHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Creates Local Loginserver Account";
|
||||
@ -130,19 +108,14 @@ namespace LoginserverCommandHandler {
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
AccountManagement::CreateLoginServerAccount(
|
||||
cmd(2).str(),
|
||||
cmd(3).str(),
|
||||
cmd("--email").str()
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = cmd(2).str();
|
||||
c.password = cmd(3).str();
|
||||
c.email = cmd("--email").str();
|
||||
|
||||
AccountManagement::CreateLoginServerAccount(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Creates Loginserver World Administrator Account";
|
||||
@ -167,12 +140,6 @@ namespace LoginserverCommandHandler {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Check user login credentials";
|
||||
@ -189,20 +156,15 @@ namespace LoginserverCommandHandler {
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
auto res = AccountManagement::CheckLoginserverUserCredentials(
|
||||
cmd(2).str(),
|
||||
cmd(3).str()
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = cmd(2).str();
|
||||
c.password = cmd(3).str();
|
||||
|
||||
LogInfo("Credentials were {0}", res != 0 ? "accepted" : "not accepted");
|
||||
auto res = AccountManagement::CheckLoginserverUserCredentials(c);
|
||||
|
||||
LogInfo("Credentials were {}", res != 0 ? "accepted" : "not accepted");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Change user login credentials";
|
||||
@ -219,18 +181,12 @@ namespace LoginserverCommandHandler {
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
AccountManagement::UpdateLoginserverUserCredentials(
|
||||
cmd(2).str(),
|
||||
cmd(3).str()
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = cmd(2).str();
|
||||
c.password = cmd(3).str();
|
||||
AccountManagement::UpdateLoginserverUserCredentials(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Check user external login credentials";
|
||||
@ -247,20 +203,14 @@ namespace LoginserverCommandHandler {
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
auto res = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
cmd(2).str(),
|
||||
cmd(3).str()
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = cmd(2).str();
|
||||
c.password = cmd(3).str();
|
||||
auto res = AccountManagement::CheckExternalLoginserverUserCredentials(c);
|
||||
|
||||
LogInfo("Credentials were {0}", res ? "accepted" : "not accepted");
|
||||
LogInfo("Credentials were {}", res ? "accepted" : "not accepted");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Update world admin account password";
|
||||
@ -277,18 +227,12 @@ namespace LoginserverCommandHandler {
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
|
||||
cmd(2).str(),
|
||||
cmd(3).str()
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = cmd(2).str();
|
||||
c.password = cmd(3).str();
|
||||
AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Checks login health using a test user";
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
#include "loginserver_webserver.h"
|
||||
#include "server_manager.h"
|
||||
#include "world_server_manager.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/json/json.h"
|
||||
#include "../common/strings.h"
|
||||
#include "account_management.h"
|
||||
#include "../common/repositories/login_api_tokens_repository.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
@ -13,9 +14,6 @@ namespace LoginserverWebserver {
|
||||
constexpr static int HTTP_RESPONSE_BAD_REQUEST = 400;
|
||||
constexpr static int HTTP_RESPONSE_UNAUTHORIZED = 401;
|
||||
|
||||
/**
|
||||
* @param api
|
||||
*/
|
||||
void RegisterRoutes(httplib::Server &api)
|
||||
{
|
||||
server.token_manager = new LoginserverWebserver::TokenManager;
|
||||
@ -27,21 +25,21 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto iter = server.server_manager->getWorldServers().begin();
|
||||
while (iter != server.server_manager->getWorldServers().end()) {
|
||||
Json::Value response;
|
||||
auto iter = server.server_manager->GetWorldServers().begin();
|
||||
for (const auto &s: server.server_manager->GetWorldServers()) {
|
||||
Json::Value row;
|
||||
row["server_long_name"] = (*iter)->GetServerLongName();
|
||||
row["server_short_name"] = (*iter)->GetServerShortName();
|
||||
row["server_list_type_id"] = (*iter)->GetServerListID();
|
||||
row["server_status"] = (*iter)->GetStatus();
|
||||
row["zones_booted"] = (*iter)->GetZonesBooted();
|
||||
row["local_ip"] = (*iter)->GetLocalIP();
|
||||
row["remote_ip"] = (*iter)->GetRemoteIP();
|
||||
row["players_online"] = (*iter)->GetPlayersOnline();
|
||||
row["world_id"] = (*iter)->GetServerId();
|
||||
row["server_long_name"] = s->GetServerLongName();
|
||||
row["server_short_name"] = s->GetServerShortName();
|
||||
row["server_list_type_id"] = s->GetServerListID();
|
||||
row["server_status"] = s->GetStatus();
|
||||
row["zones_booted"] = s->GetZonesBooted();
|
||||
row["local_ip"] = s->GetLocalIP();
|
||||
row["remote_ip"] = s->GetRemoteIP();
|
||||
row["players_online"] = s->GetPlayersOnline();
|
||||
row["world_id"] = s->GetServerId();
|
||||
|
||||
response.append(row);
|
||||
++iter;
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
@ -54,10 +52,10 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
std::string email = request_body.get("email", "").asString();
|
||||
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = req.get("username", "").asString();
|
||||
std::string password = req.get("password", "").asString();
|
||||
std::string email = req.get("email", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
@ -67,7 +65,12 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
int32 account_created_id = AccountManagement::CreateLoginServerAccount(username, password, email);
|
||||
LoginAccountContext c;
|
||||
c.username = username;
|
||||
c.password = password;
|
||||
c.email = email;
|
||||
|
||||
int32 account_created_id = AccountManagement::CreateLoginServerAccount(c);
|
||||
if (account_created_id > 0) {
|
||||
response["message"] = "Account created successfully!";
|
||||
response["data"]["account_id"] = account_created_id;
|
||||
@ -91,11 +94,11 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
std::string email = request_body.get("email", "").asString();
|
||||
uint32 login_account_id = request_body.get("login_account_id", "").asInt();
|
||||
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = req.get("username", "").asString();
|
||||
std::string password = req.get("password", "").asString();
|
||||
std::string email = req.get("email", "").asString();
|
||||
uint32 login_account_id = req.get("login_account_id", "").asInt();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
@ -105,14 +108,14 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string source_loginserver = "eqemu";
|
||||
int32 account_created_id = AccountManagement::CreateLoginServerAccount(
|
||||
username,
|
||||
password,
|
||||
email,
|
||||
source_loginserver,
|
||||
login_account_id
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = username;
|
||||
c.password = password;
|
||||
c.email = email;
|
||||
c.source_loginserver = "eqemu";
|
||||
c.login_account_id = login_account_id;
|
||||
|
||||
int32 account_created_id = AccountManagement::CreateLoginServerAccount(c);
|
||||
|
||||
if (account_created_id > 0) {
|
||||
response["message"] = "Account created successfully!";
|
||||
@ -137,9 +140,9 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = req.get("username", "").asString();
|
||||
std::string password = req.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
@ -149,11 +152,11 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 login_account_id = AccountManagement::CheckLoginserverUserCredentials(
|
||||
username,
|
||||
password
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = username;
|
||||
c.password = password;
|
||||
|
||||
uint32 login_account_id = AccountManagement::CheckLoginserverUserCredentials(c);
|
||||
if (login_account_id > 0) {
|
||||
response["message"] = "Credentials valid!";
|
||||
response["data"]["account_id"] = login_account_id;
|
||||
@ -173,9 +176,9 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = req.get("username", "").asString();
|
||||
std::string password = req.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
@ -185,24 +188,20 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
||||
username
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = username;
|
||||
c.password = password;
|
||||
|
||||
if (!login_server_account.loaded) {
|
||||
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
|
||||
if (!a.id) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Failed to find associated loginserver account!";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
bool credentials_valid = AccountManagement::UpdateLoginserverUserCredentials(
|
||||
username,
|
||||
password
|
||||
);
|
||||
|
||||
if (credentials_valid) {
|
||||
bool success = AccountManagement::UpdateLoginserverUserCredentials(c);
|
||||
if (success) {
|
||||
response["message"] = "Loginserver account credentials updated!";
|
||||
}
|
||||
else {
|
||||
@ -214,16 +213,15 @@ namespace LoginserverWebserver {
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
api.Post(
|
||||
"/v1/account/credentials/update/external", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanWrite(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = req.get("username", "").asString();
|
||||
std::string password = req.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
@ -234,25 +232,20 @@ namespace LoginserverWebserver {
|
||||
|
||||
std::string source_loginserver = "eqemu";
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
||||
username,
|
||||
source_loginserver
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = username;
|
||||
c.password = password;
|
||||
c.source_loginserver = source_loginserver;
|
||||
|
||||
if (!login_server_account.loaded) {
|
||||
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
|
||||
if (!a.id) {
|
||||
response["error"] = "Failed to find associated loginserver account!";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
bool credentials_valid = AccountManagement::UpdateLoginserverUserCredentials(
|
||||
username,
|
||||
password,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
if (credentials_valid) {
|
||||
bool success = AccountManagement::UpdateLoginserverUserCredentials(c);
|
||||
if (success) {
|
||||
response["message"] = "Loginserver account credentials updated!";
|
||||
}
|
||||
else {
|
||||
@ -269,9 +262,9 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = req.get("username", "").asString();
|
||||
std::string password = req.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
@ -280,10 +273,10 @@ namespace LoginserverWebserver {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
username,
|
||||
password
|
||||
);
|
||||
LoginAccountContext c;
|
||||
c.username = username;
|
||||
c.password = password;
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(c);
|
||||
|
||||
if (account_id > 0) {
|
||||
response["message"] = "Credentials valid!";
|
||||
@ -301,7 +294,7 @@ namespace LoginserverWebserver {
|
||||
api.Get(
|
||||
"/probes/healthcheck", [](const httplib::Request &request, httplib::Response &res) {
|
||||
Json::Value response;
|
||||
uint32 login_response = AccountManagement::HealthCheckUserLogin();
|
||||
uint32 login_response = AccountManagement::HealthCheckUserLogin();
|
||||
|
||||
response["status"] = login_response;
|
||||
if (login_response == 0) {
|
||||
@ -317,10 +310,6 @@ namespace LoginserverWebserver {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param payload
|
||||
* @param res
|
||||
*/
|
||||
void SendResponse(const Json::Value &payload, httplib::Response &res)
|
||||
{
|
||||
if (res.get_header_value("response_set") == "true") {
|
||||
@ -342,10 +331,6 @@ namespace LoginserverWebserver {
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param payload
|
||||
* @param res
|
||||
*/
|
||||
Json::Value ParseRequestBody(const httplib::Request &request)
|
||||
{
|
||||
Json::Value request_body;
|
||||
@ -364,13 +349,9 @@ namespace LoginserverWebserver {
|
||||
return request_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param res
|
||||
*/
|
||||
bool LoginserverWebserver::TokenManager::AuthCanRead(const httplib::Request &request, httplib::Response &res)
|
||||
{
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
LoginserverWebserver::TokenManager::Token
|
||||
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||
|
||||
if (!user_token.can_read) {
|
||||
@ -384,7 +365,7 @@ namespace LoginserverWebserver {
|
||||
res.set_header("response_set", "true");
|
||||
|
||||
LogWarning(
|
||||
"AuthCanRead access failure remote_address [{0}] user_agent [{1}]",
|
||||
"AuthCanRead access failure remote_address [{}] user_agent [{}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent
|
||||
);
|
||||
@ -395,13 +376,9 @@ namespace LoginserverWebserver {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param res
|
||||
*/
|
||||
bool LoginserverWebserver::TokenManager::AuthCanWrite(const httplib::Request &request, httplib::Response &res)
|
||||
{
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
LoginserverWebserver::TokenManager::Token
|
||||
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||
|
||||
if (!user_token.can_write) {
|
||||
@ -415,7 +392,7 @@ namespace LoginserverWebserver {
|
||||
res.set_header("response_set", "true");
|
||||
|
||||
LogWarning(
|
||||
"AuthCanWrite access failure remote_address [{0}] user_agent [{1}]",
|
||||
"AuthCanWrite access failure remote_address [{}] user_agent [{}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent
|
||||
);
|
||||
@ -426,20 +403,16 @@ namespace LoginserverWebserver {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
LoginserverWebserver::TokenManager::Token
|
||||
LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(
|
||||
const httplib::Request &request
|
||||
)
|
||||
{
|
||||
std::string authorization_key;
|
||||
|
||||
LoginserverWebserver::TokenManager::token_data user_token{};
|
||||
LoginserverWebserver::TokenManager::Token user_token{};
|
||||
|
||||
for (const auto &header : request.headers) {
|
||||
for (const auto &header: request.headers) {
|
||||
auto header_key = header.first;
|
||||
auto header_value = header.second;
|
||||
if (header_key == "Authorization") {
|
||||
@ -460,7 +433,7 @@ namespace LoginserverWebserver {
|
||||
}
|
||||
|
||||
LogDebug(
|
||||
"Authentication Request | remote_address [{0}] user_agent [{1}] authorization_key [{2}] request_path [{3}]",
|
||||
"Authentication Request | remote_address [{}] user_agent [{}] authorization_key [{}] request_path [{}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent,
|
||||
authorization_key,
|
||||
@ -470,43 +443,24 @@ namespace LoginserverWebserver {
|
||||
return user_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads API Tokens
|
||||
*/
|
||||
void TokenManager::LoadApiTokens()
|
||||
{
|
||||
auto results = server.db->GetLoginserverApiTokens();
|
||||
int token_count = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
LoginserverWebserver::TokenManager::token_data token_data;
|
||||
token_data.token = row[0];
|
||||
token_data.can_write = Strings::ToInt(row[1]) > 0;
|
||||
token_data.can_read = Strings::ToInt(row[2]) > 0;
|
||||
int token_count = 0;
|
||||
|
||||
LogDebug(
|
||||
"Inserting api token to internal list [{0}] write {1} read {2}",
|
||||
token_data.token,
|
||||
token_data.can_read,
|
||||
token_data.can_write
|
||||
);
|
||||
|
||||
server.token_manager->loaded_api_tokens.emplace(
|
||||
std::make_pair(
|
||||
token_data.token,
|
||||
token_data
|
||||
)
|
||||
);
|
||||
for (auto &t: LoginApiTokensRepository::GetWhere(database, "TRUE ORDER BY id ASC")) {
|
||||
LoginserverWebserver::TokenManager::Token td;
|
||||
td.id = t.id;
|
||||
td.token = t.token;
|
||||
td.can_write = t.can_write;
|
||||
td.can_read = t.can_read;
|
||||
|
||||
server.token_manager->loaded_api_tokens.emplace(std::make_pair(td.token, td));
|
||||
token_count++;
|
||||
}
|
||||
|
||||
LogInfo("Loaded [{}] API token(s)", token_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
bool TokenManager::TokenExists(const std::string &token)
|
||||
{
|
||||
auto it = server.token_manager->loaded_api_tokens.find(token);
|
||||
@ -514,11 +468,7 @@ namespace LoginserverWebserver {
|
||||
return !(it == server.token_manager->loaded_api_tokens.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
LoginserverWebserver::TokenManager::token_data TokenManager::GetToken(
|
||||
LoginserverWebserver::TokenManager::Token TokenManager::GetToken(
|
||||
const std::string &token
|
||||
)
|
||||
{
|
||||
|
||||
@ -12,7 +12,8 @@ namespace LoginserverWebserver {
|
||||
public:
|
||||
TokenManager() = default;
|
||||
|
||||
struct token_data {
|
||||
struct Token {
|
||||
int id;
|
||||
std::string token;
|
||||
bool can_read;
|
||||
bool can_write;
|
||||
@ -20,12 +21,12 @@ namespace LoginserverWebserver {
|
||||
std::string remote_address;
|
||||
};
|
||||
|
||||
std::map<std::string, token_data> loaded_api_tokens{};
|
||||
std::map<std::string, Token> loaded_api_tokens{};
|
||||
|
||||
void LoadApiTokens();
|
||||
static bool TokenExists(const std::string &token);
|
||||
token_data GetToken(const std::string &token);
|
||||
static token_data CheckApiAuthorizationHeaders(const httplib::Request &request);
|
||||
Token GetToken(const std::string &token);
|
||||
static Token CheckApiAuthorizationHeaders(const httplib::Request &request);
|
||||
static bool AuthCanRead(const httplib::Request &request, httplib::Response &res);
|
||||
static bool AuthCanWrite(const httplib::Request &request, httplib::Response &res);
|
||||
};
|
||||
|
||||
@ -12,18 +12,23 @@
|
||||
#include "loginserver_command_handler.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/path_manager.h"
|
||||
#include "../common/database.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/zone_store.h"
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
LoginServer server;
|
||||
EQEmuLogSys LogSys;
|
||||
bool run_server = true;
|
||||
PathManager path;
|
||||
LoginServer server;
|
||||
EQEmuLogSys LogSys;
|
||||
bool run_server = true;
|
||||
PathManager path;
|
||||
Database database;
|
||||
PlayerEventLogs player_event_logs;
|
||||
ZoneStore zone_store;
|
||||
|
||||
void ResolveAddresses();
|
||||
void CatchSignal(int sig_num)
|
||||
{
|
||||
}
|
||||
@ -32,14 +37,16 @@ void LoadDatabaseConnection()
|
||||
{
|
||||
LogInfo("MySQL Database Init");
|
||||
|
||||
server.db = new Database(
|
||||
if (!database.Connect(
|
||||
server.config.GetVariableString("database", "host", "localhost"),
|
||||
server.config.GetVariableString("database", "user", "root"),
|
||||
server.config.GetVariableString("database", "password", ""),
|
||||
server.config.GetVariableString("database", "host", "localhost"),
|
||||
server.config.GetVariableString("database", "port", "3306"),
|
||||
server.config.GetVariableString("database", "db", "peq")
|
||||
);
|
||||
|
||||
server.config.GetVariableString("database", "db", "peq"),
|
||||
server.config.GetVariableInt("database", "port", 3306)
|
||||
)) {
|
||||
LogError("Cannot continue without a database connection");
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadServerConfig()
|
||||
@ -49,9 +56,6 @@ void LoadServerConfig()
|
||||
);
|
||||
LogInfo("Config System Init");
|
||||
|
||||
/**
|
||||
* Worldservers
|
||||
*/
|
||||
server.options.RejectDuplicateServers(
|
||||
server.config.GetVariableBool(
|
||||
"worldservers",
|
||||
@ -82,41 +86,33 @@ void LoadServerConfig()
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Expansion Display Settings
|
||||
*/
|
||||
server.options.DisplayExpansions(
|
||||
server.config.GetVariableBool(
|
||||
"client_configuration",
|
||||
"display_expansions",
|
||||
false
|
||||
)); //disable by default
|
||||
)
|
||||
);
|
||||
server.options.MaxExpansions(
|
||||
server.config.GetVariableInt(
|
||||
"client_configuration",
|
||||
"max_expansions_mask",
|
||||
67108863
|
||||
)); //enable display of all expansions
|
||||
|
||||
/**
|
||||
* Account
|
||||
*/
|
||||
server.options.AutoCreateAccounts(server.config.GetVariableBool("account", "auto_create_accounts", true));
|
||||
server.options.AutoLinkAccounts(server.config.GetVariableBool("account", "auto_link_accounts", false));
|
||||
|
||||
#ifdef LSPX
|
||||
server.options.EQEmuLoginServerAddress(
|
||||
server.config.GetVariableString(
|
||||
"general",
|
||||
"eqemu_loginserver_address",
|
||||
"login.eqemulator.net:5999"
|
||||
)
|
||||
);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Default Loginserver Name (Don't change)
|
||||
*/
|
||||
server.options.AutoCreateAccounts(server.config.GetVariableBool("account", "auto_create_accounts", true));
|
||||
|
||||
if (std::getenv("LSPX")) {
|
||||
server.options.EQEmuLoginServerAddress(
|
||||
server.config.GetVariableString(
|
||||
"general",
|
||||
"eqemu_loginserver_address",
|
||||
"login.eqemulator.net:5999"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
server.options.DefaultLoginServerName(
|
||||
server.config.GetVariableString(
|
||||
"general",
|
||||
@ -125,10 +121,6 @@ void LoadServerConfig()
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Security
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
server.options.EncryptionMode(server.config.GetVariableInt("security", "mode", 13));
|
||||
#else
|
||||
@ -136,14 +128,6 @@ void LoadServerConfig()
|
||||
#endif
|
||||
|
||||
server.options.AllowTokenLogin(server.config.GetVariableBool("security", "allow_token_login", false));
|
||||
server.options.AllowPasswordLogin(server.config.GetVariableBool("security", "allow_password_login", true));
|
||||
server.options.UpdateInsecurePasswords(
|
||||
server.config.GetVariableBool(
|
||||
"security",
|
||||
"update_insecure_passwords",
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void start_web_server()
|
||||
@ -151,7 +135,7 @@ void start_web_server()
|
||||
Sleep(1);
|
||||
|
||||
int web_api_port = server.config.GetVariableInt("web_api", "port", 6000);
|
||||
LogInfo("Webserver API now listening on port [{0}]", web_api_port);
|
||||
LogInfo("Webserver API now listening on port [{}]", web_api_port);
|
||||
|
||||
httplib::Server api;
|
||||
|
||||
@ -180,9 +164,7 @@ int main(int argc, char **argv)
|
||||
|
||||
path.LoadPaths();
|
||||
|
||||
/**
|
||||
* Command handler
|
||||
*/
|
||||
// command handler
|
||||
if (argc > 1) {
|
||||
LogSys.SilenceConsoleLogging();
|
||||
|
||||
@ -197,43 +179,23 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
LoadServerConfig();
|
||||
|
||||
/**
|
||||
* mysql connect
|
||||
*/
|
||||
LoadDatabaseConnection();
|
||||
|
||||
if (argc == 1) {
|
||||
LogSys.SetDatabase(server.db)
|
||||
LogSys.SetDatabase(&database)
|
||||
->SetLogPath("logs")
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* make sure our database got created okay, otherwise cleanup and exit
|
||||
*/
|
||||
if (!server.db) {
|
||||
LogError("Database Initialization Failure");
|
||||
LogInfo("Log System Shutdown");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* create server manager
|
||||
*/
|
||||
LogInfo("Server Manager Init");
|
||||
server.server_manager = new ServerManager();
|
||||
server.server_manager = new WorldServerManager();
|
||||
if (!server.server_manager) {
|
||||
LogError("Server Manager Failed to Start");
|
||||
LogInfo("Database System Shutdown");
|
||||
delete server.db;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* create client manager
|
||||
*/
|
||||
LogInfo("Client Manager Init");
|
||||
server.client_manager = new ClientManager();
|
||||
if (!server.client_manager) {
|
||||
@ -242,7 +204,6 @@ int main(int argc, char **argv)
|
||||
delete server.server_manager;
|
||||
|
||||
LogInfo("Database System Shutdown");
|
||||
delete server.db;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -256,37 +217,33 @@ int main(int argc, char **argv)
|
||||
|
||||
LogInfo("Server Started");
|
||||
|
||||
/**
|
||||
* Web API
|
||||
*/
|
||||
bool web_api_enabled = server.config.GetVariableBool("web_api", "enabled", true);
|
||||
if (web_api_enabled) {
|
||||
std::thread web_api_thread(start_web_server);
|
||||
web_api_thread.detach();
|
||||
}
|
||||
|
||||
LogInfo("[Config] [Account] CanAutoCreateAccounts [{0}]", server.options.CanAutoCreateAccounts());
|
||||
LogInfo("[Config] [ClientConfiguration] DisplayExpansions [{0}]", server.options.IsDisplayExpansions());
|
||||
LogInfo("[Config] [ClientConfiguration] MaxExpansions [{0}]", server.options.GetMaxExpansions());
|
||||
LogInfo("[Config] [Account] CanAutoCreateAccounts [{}]", server.options.CanAutoCreateAccounts());
|
||||
LogInfo("[Config] [ClientConfiguration] DisplayExpansions [{}]", server.options.IsDisplayExpansions());
|
||||
LogInfo("[Config] [ClientConfiguration] MaxExpansions [{}]", server.options.GetMaxExpansions());
|
||||
|
||||
#ifdef LSPX
|
||||
LogInfo("[Config] [Account] CanAutoLinkAccounts [{0}]", server.options.CanAutoLinkAccounts());
|
||||
#endif
|
||||
LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{0}]", server.options.IsRejectingDuplicateServers());
|
||||
LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{0}]", server.options.IsUnregisteredAllowed());
|
||||
LogInfo("[Config] [WorldServer] ShowPlayerCount [{0}]", server.options.IsShowPlayerCountEnabled());
|
||||
if (std::getenv("LSPX")) {
|
||||
LogInfo("[Config] [Account] LSPX [on]");
|
||||
}
|
||||
|
||||
LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{}]", server.options.IsRejectingDuplicateServers());
|
||||
LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{}]", server.options.IsUnregisteredAllowed());
|
||||
LogInfo("[Config] [WorldServer] ShowPlayerCount [{}]", server.options.IsShowPlayerCountEnabled());
|
||||
LogInfo(
|
||||
"[Config] [WorldServer] DevAndTestServersListBottom [{0}]",
|
||||
"[Config] [WorldServer] DevAndTestServersListBottom [{}]",
|
||||
server.options.IsWorldDevTestServersListBottom()
|
||||
);
|
||||
LogInfo(
|
||||
"[Config] [WorldServer] SpecialCharactersStartListBottom [{0}]",
|
||||
"[Config] [WorldServer] SpecialCharactersStartListBottom [{}]",
|
||||
server.options.IsWorldSpecialCharacterStartListBottom()
|
||||
);
|
||||
LogInfo("[Config] [Security] GetEncryptionMode [{0}]", server.options.GetEncryptionMode());
|
||||
LogInfo("[Config] [Security] IsTokenLoginAllowed [{0}]", server.options.IsTokenLoginAllowed());
|
||||
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
|
||||
LogInfo("[Config] [Security] IsUpdatingInsecurePasswords [{0}]", server.options.IsUpdatingInsecurePasswords());
|
||||
LogInfo("[Config] [Security] GetEncryptionMode [{}]", server.options.GetEncryptionMode());
|
||||
LogInfo("[Config] [Security] IsTokenLoginAllowed [{}]", server.options.IsTokenLoginAllowed());
|
||||
|
||||
Timer keepalive(INTERSERVER_TIMER); // does auto-reconnect
|
||||
|
||||
@ -295,7 +252,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (keepalive.Check()) {
|
||||
keepalive.Start();
|
||||
server.db->ping();
|
||||
database.ping();
|
||||
}
|
||||
|
||||
if (!run_server) {
|
||||
@ -319,8 +276,5 @@ int main(int argc, char **argv)
|
||||
LogInfo("Server Manager Shutdown");
|
||||
delete server.server_manager;
|
||||
|
||||
LogInfo("Database System Shutdown");
|
||||
delete server.db;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,124 +1,55 @@
|
||||
#ifndef EQEMU_OPTIONS_H
|
||||
#define EQEMU_OPTIONS_H
|
||||
|
||||
/**
|
||||
* Collects options on one object, because having a bunch of global variables floating around is
|
||||
* really ugly and just a little dangerous.
|
||||
*/
|
||||
class Options {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor: Default options
|
||||
*/
|
||||
Options() :
|
||||
allow_unregistered(true),
|
||||
display_expansions(false),
|
||||
max_expansions_mask(0),
|
||||
encryption_mode(5),
|
||||
reject_duplicate_servers(false),
|
||||
allow_password_login(true),
|
||||
allow_token_login(false),
|
||||
auto_create_accounts(false) {}
|
||||
m_allow_unregistered(true),
|
||||
m_display_expansions(false),
|
||||
m_max_expansions_mask(0),
|
||||
m_encryption_mode(14),
|
||||
m_reject_duplicate_servers(false),
|
||||
m_allow_token_login(false),
|
||||
m_auto_create_accounts(false) {}
|
||||
|
||||
/**
|
||||
* Sets allow_unregistered.
|
||||
*/
|
||||
inline void AllowUnregistered(bool b) { allow_unregistered = b; }
|
||||
|
||||
/**
|
||||
* Returns the value of expansion display settings.
|
||||
*/
|
||||
inline void DisplayExpansions(bool b) { display_expansions = b; }
|
||||
inline void MaxExpansions(int i) { max_expansions_mask = i; }
|
||||
inline bool IsDisplayExpansions() const { return display_expansions; }
|
||||
inline int GetMaxExpansions() const { return max_expansions_mask; }
|
||||
|
||||
/**
|
||||
* Returns the value of allow_unregistered.
|
||||
*/
|
||||
inline bool IsUnregisteredAllowed() const { return allow_unregistered; }
|
||||
|
||||
/**
|
||||
* Sets encryption_mode.
|
||||
*/
|
||||
inline void EncryptionMode(int m) { encryption_mode = m; }
|
||||
|
||||
/**
|
||||
* Returns the value of encryption_mode.
|
||||
*/
|
||||
inline int GetEncryptionMode() const { return encryption_mode; }
|
||||
|
||||
/**
|
||||
* Sets whether we are rejecting duplicate servers or not.
|
||||
*/
|
||||
inline void RejectDuplicateServers(bool b) { reject_duplicate_servers = b; }
|
||||
|
||||
/**
|
||||
* Returns whether we are rejecting duplicate servers or not.
|
||||
*/
|
||||
inline bool IsRejectingDuplicateServers() { return reject_duplicate_servers; }
|
||||
|
||||
inline void AllowTokenLogin(bool b) { allow_token_login = b; }
|
||||
inline bool IsTokenLoginAllowed() const { return allow_token_login; }
|
||||
|
||||
inline void AllowPasswordLogin(bool b) { allow_password_login = b; }
|
||||
inline bool IsPasswordLoginAllowed() const { return allow_password_login; }
|
||||
|
||||
inline void AutoCreateAccounts(bool b) { auto_create_accounts = b; }
|
||||
inline bool CanAutoCreateAccounts() const { return auto_create_accounts; }
|
||||
|
||||
inline void AutoLinkAccounts(bool b) { auto_link_accounts = b; }
|
||||
inline bool CanAutoLinkAccounts() const { return auto_link_accounts; }
|
||||
|
||||
inline void EQEmuLoginServerAddress(const std::string& v) { eqemu_loginserver_address = v; }
|
||||
inline std::string GetEQEmuLoginServerAddress() const { return eqemu_loginserver_address; }
|
||||
|
||||
inline void DefaultLoginServerName(const std::string& v) { default_loginserver_name = v; }
|
||||
inline std::string GetDefaultLoginServerName() const { return default_loginserver_name; }
|
||||
|
||||
inline void UpdateInsecurePasswords(bool b) { update_insecure_passwords = b; }
|
||||
inline bool IsUpdatingInsecurePasswords() const { return update_insecure_passwords; }
|
||||
|
||||
inline bool IsShowPlayerCountEnabled() const
|
||||
{
|
||||
return show_player_count;
|
||||
}
|
||||
inline void SetShowPlayerCount(bool show_player_count)
|
||||
{
|
||||
Options::show_player_count = show_player_count;
|
||||
}
|
||||
inline bool IsWorldDevTestServersListBottom() const { return world_dev_test_servers_list_bottom; }
|
||||
inline void SetWorldDevTestServersListBottom(bool dev_test_servers_list_bottom)
|
||||
{
|
||||
Options::world_dev_test_servers_list_bottom = dev_test_servers_list_bottom;
|
||||
}
|
||||
|
||||
inline bool IsWorldSpecialCharacterStartListBottom() const
|
||||
{
|
||||
return world_special_character_start_list_bottom;
|
||||
}
|
||||
inline void SetWorldSpecialCharacterStartListBottom(bool world_special_character_start_list_bottom)
|
||||
{
|
||||
Options::world_special_character_start_list_bottom = world_special_character_start_list_bottom;
|
||||
}
|
||||
inline void AllowUnregistered(bool b) { m_allow_unregistered = b; }
|
||||
inline void DisplayExpansions(bool b) { m_display_expansions = b; }
|
||||
inline void MaxExpansions(int i) { m_max_expansions_mask = i; }
|
||||
inline bool IsDisplayExpansions() const { return m_display_expansions; }
|
||||
inline int GetMaxExpansions() const { return m_max_expansions_mask; }
|
||||
inline bool IsUnregisteredAllowed() const { return m_allow_unregistered; }
|
||||
inline void EncryptionMode(int m) { m_encryption_mode = m; }
|
||||
inline int GetEncryptionMode() const { return m_encryption_mode; }
|
||||
inline void RejectDuplicateServers(bool b) { m_reject_duplicate_servers = b; }
|
||||
inline bool IsRejectingDuplicateServers() { return m_reject_duplicate_servers; }
|
||||
inline void AllowTokenLogin(bool b) { m_allow_token_login = b; }
|
||||
inline bool IsTokenLoginAllowed() const { return m_allow_token_login; }
|
||||
inline void AutoCreateAccounts(bool b) { m_auto_create_accounts = b; }
|
||||
inline bool CanAutoCreateAccounts() const { return m_auto_create_accounts; }
|
||||
inline void EQEmuLoginServerAddress(const std::string &v) { m_eqemu_loginserver_address = v; }
|
||||
inline std::string GetEQEmuLoginServerAddress() const { return m_eqemu_loginserver_address; }
|
||||
inline void DefaultLoginServerName(const std::string &v) { m_default_loginserver_name = v; }
|
||||
inline std::string GetDefaultLoginServerName() const { return m_default_loginserver_name; }
|
||||
inline bool IsShowPlayerCountEnabled() const { return m_show_player_count; }
|
||||
inline void SetShowPlayerCount(bool show_player_count) { show_player_count = show_player_count; }
|
||||
inline bool IsWorldDevTestServersListBottom() const { return m_world_dev_list_bottom; }
|
||||
inline void SetWorldDevTestServersListBottom(bool list_bottom) { m_world_dev_list_bottom = list_bottom; }
|
||||
inline bool IsWorldSpecialCharacterStartListBottom() const { return m_special_char_list_bottom; }
|
||||
inline void SetWorldSpecialCharacterStartListBottom(bool list_bottom) { m_special_char_list_bottom = list_bottom; }
|
||||
|
||||
private:
|
||||
bool allow_unregistered;
|
||||
bool display_expansions;
|
||||
bool reject_duplicate_servers;
|
||||
bool world_dev_test_servers_list_bottom;
|
||||
bool world_special_character_start_list_bottom;
|
||||
bool allow_token_login;
|
||||
bool allow_password_login;
|
||||
bool show_player_count;
|
||||
bool auto_create_accounts;
|
||||
bool auto_link_accounts;
|
||||
bool update_insecure_passwords;
|
||||
int encryption_mode;
|
||||
int max_expansions_mask;
|
||||
std::string eqemu_loginserver_address;
|
||||
std::string default_loginserver_name;
|
||||
bool m_allow_unregistered;
|
||||
bool m_display_expansions;
|
||||
bool m_reject_duplicate_servers;
|
||||
bool m_world_dev_list_bottom;
|
||||
bool m_special_char_list_bottom;
|
||||
bool m_allow_token_login;
|
||||
bool m_show_player_count;
|
||||
bool m_auto_create_accounts;
|
||||
int m_encryption_mode;
|
||||
int m_max_expansions_mask;
|
||||
std::string m_eqemu_loginserver_address;
|
||||
std::string m_default_loginserver_name;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,248 +0,0 @@
|
||||
#include "server_manager.h"
|
||||
#include "login_server.h"
|
||||
#include "login_types.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/ip_util.h"
|
||||
|
||||
extern LoginServer server;
|
||||
extern bool run_server;
|
||||
|
||||
ServerManager::ServerManager()
|
||||
{
|
||||
int listen_port = server.config.GetVariableInt("general", "listen_port", 5998);
|
||||
|
||||
m_server_connection = std::make_unique<EQ::Net::ServertalkServer>();
|
||||
EQ::Net::ServertalkServerOptions opts;
|
||||
opts.port = listen_port;
|
||||
opts.ipv6 = false;
|
||||
m_server_connection->Listen(opts);
|
||||
|
||||
LogInfo("Loginserver now listening on port [{0}]", listen_port);
|
||||
|
||||
m_server_connection->OnConnectionIdentified(
|
||||
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> world_connection) {
|
||||
LogInfo(
|
||||
"New World Server connection from {0}:{1}",
|
||||
world_connection->Handle()->RemoteIP(),
|
||||
world_connection->Handle()->RemotePort()
|
||||
);
|
||||
|
||||
auto iter = m_world_servers.begin();
|
||||
while (iter != m_world_servers.end()) {
|
||||
if ((*iter)->GetConnection()->Handle()->RemoteIP().compare(world_connection->Handle()->RemoteIP()) ==
|
||||
0 &&
|
||||
(*iter)->GetConnection()->Handle()->RemotePort() == world_connection->Handle()->RemotePort()) {
|
||||
|
||||
LogInfo(
|
||||
"World server already existed for {0}:{1}, removing existing connection.",
|
||||
world_connection->Handle()->RemoteIP(),
|
||||
world_connection->Handle()->RemotePort()
|
||||
);
|
||||
|
||||
m_world_servers.erase(iter);
|
||||
break;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
m_world_servers.push_back(std::make_unique<WorldServer>(world_connection));
|
||||
}
|
||||
);
|
||||
|
||||
m_server_connection->OnConnectionRemoved(
|
||||
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
|
||||
auto iter = m_world_servers.begin();
|
||||
while (iter != m_world_servers.end()) {
|
||||
if ((*iter)->GetConnection()->GetUUID() == c->GetUUID()) {
|
||||
LogInfo(
|
||||
"World server {0} has been disconnected, removing.",
|
||||
(*iter)->GetServerLongName()
|
||||
);
|
||||
m_world_servers.erase(iter);
|
||||
return;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ServerManager::~ServerManager() = default;
|
||||
|
||||
/**
|
||||
* @param client
|
||||
* @param sequence
|
||||
* @return
|
||||
*/
|
||||
std::unique_ptr<EQApplicationPacket> ServerManager::CreateServerListPacket(Client *client, uint32 sequence)
|
||||
{
|
||||
unsigned int server_count = 0;
|
||||
in_addr in{};
|
||||
in.s_addr = client->GetConnection()->GetRemoteIP();
|
||||
std::string client_ip = inet_ntoa(in);
|
||||
|
||||
LogDebug("ServerManager::CreateServerListPacket via client address [{0}]", client_ip);
|
||||
|
||||
for (const auto& world_server : m_world_servers)
|
||||
{
|
||||
if (world_server->IsAuthorized()) {
|
||||
++server_count;
|
||||
}
|
||||
}
|
||||
|
||||
SerializeBuffer buf;
|
||||
|
||||
// LoginBaseMessage_Struct header
|
||||
buf.WriteInt32(sequence);
|
||||
buf.WriteInt8(0);
|
||||
buf.WriteInt8(0);
|
||||
buf.WriteInt32(0);
|
||||
|
||||
// LoginBaseReplyMessage_Struct
|
||||
buf.WriteInt8(true); // success (no error)
|
||||
buf.WriteInt32(0x65); // 101 "No Error" eqlsstr
|
||||
buf.WriteString("");
|
||||
|
||||
// ServerListReply_Struct
|
||||
buf.WriteInt32(server_count);
|
||||
|
||||
for (const auto& world_server : m_world_servers)
|
||||
{
|
||||
if (!world_server->IsAuthorized()) {
|
||||
LogDebug(
|
||||
"ServerManager::CreateServerListPacket | Server [{}] via IP [{}] is not authorized to be listed",
|
||||
world_server->GetServerLongName(),
|
||||
world_server->GetConnection()->Handle()->RemoteIP()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool use_local_ip = false;
|
||||
|
||||
std::string world_ip = world_server->GetConnection()->Handle()->RemoteIP();
|
||||
if (world_ip == client_ip || IpUtil::IsIpInPrivateRfc1918(client_ip)) {
|
||||
use_local_ip = true;
|
||||
}
|
||||
|
||||
LogDebug(
|
||||
"CreateServerListPacket | Building list entry | Client [{}] IP [{}] Server Long Name [{}] Server IP [{}] ({})",
|
||||
client->GetAccountName(),
|
||||
client_ip,
|
||||
world_server->GetServerLongName(),
|
||||
use_local_ip ? world_server->GetLocalIP() : world_server->GetRemoteIP(),
|
||||
use_local_ip ? "Local" : "Remote"
|
||||
);
|
||||
|
||||
world_server->SerializeForClientServerList(buf, use_local_ip, client->GetClientVersion());
|
||||
}
|
||||
|
||||
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param server_id
|
||||
* @param client_account_id
|
||||
* @param client_loginserver
|
||||
*/
|
||||
void ServerManager::SendUserToWorldRequest(
|
||||
unsigned int server_id,
|
||||
unsigned int client_account_id,
|
||||
const std::string &client_loginserver
|
||||
)
|
||||
{
|
||||
auto iter = m_world_servers.begin();
|
||||
bool found = false;
|
||||
while (iter != m_world_servers.end()) {
|
||||
if ((*iter)->GetServerId() == server_id) {
|
||||
EQ::Net::DynamicPacket outapp;
|
||||
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
|
||||
|
||||
auto *r = (UsertoWorldRequest_Struct *) outapp.Data();
|
||||
r->worldid = server_id;
|
||||
r->lsaccountid = client_account_id;
|
||||
strncpy(r->login, &client_loginserver[0], 64);
|
||||
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp);
|
||||
found = true;
|
||||
|
||||
LogNetcode(
|
||||
"[UsertoWorldRequest] [Size: {}]\n{}",
|
||||
outapp.Length(),
|
||||
outapp.ToString()
|
||||
);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
LogError("Client requested a user to world but supplied an invalid id of {0}", server_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param ignore
|
||||
* @return
|
||||
*/
|
||||
bool ServerManager::ServerExists(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
WorldServer *ignore
|
||||
)
|
||||
{
|
||||
auto iter = m_world_servers.begin();
|
||||
while (iter != m_world_servers.end()) {
|
||||
if ((*iter).get() == ignore) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*iter)->GetServerLongName() == server_long_name && (*iter)->GetServerShortName() == server_short_name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param ignore
|
||||
*/
|
||||
void ServerManager::DestroyServerByName(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
WorldServer *ignore
|
||||
)
|
||||
{
|
||||
auto iter = m_world_servers.begin();
|
||||
while (iter != m_world_servers.end()) {
|
||||
if ((*iter).get() == ignore) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*iter)->GetServerLongName().compare(server_long_name) == 0 &&
|
||||
(*iter)->GetServerShortName().compare(server_short_name) == 0) {
|
||||
(*iter)->GetConnection()->Handle()->Disconnect();
|
||||
iter = m_world_servers.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
const std::list<std::unique_ptr<WorldServer>> &ServerManager::getWorldServers() const
|
||||
{
|
||||
return m_world_servers;
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
#ifndef EQEMU_SERVERMANAGER_H
|
||||
#define EQEMU_SERVERMANAGER_H
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "world_server.h"
|
||||
#include "client.h"
|
||||
#include <list>
|
||||
|
||||
/**
|
||||
* Server manager class, deals with management of the world servers
|
||||
*/
|
||||
class ServerManager {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor, sets up the TCP server and starts listening
|
||||
*/
|
||||
ServerManager();
|
||||
|
||||
/**
|
||||
* Destructor, shuts down the TCP server.
|
||||
*/
|
||||
~ServerManager();
|
||||
|
||||
/**
|
||||
* Sends a request to world to see if the client is banned or suspended
|
||||
*
|
||||
* @param server_id
|
||||
* @param client_account_id
|
||||
* @param client_loginserver
|
||||
*/
|
||||
void SendUserToWorldRequest(
|
||||
unsigned int server_id,
|
||||
unsigned int client_account_id,
|
||||
const std::string &client_loginserver
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a server list packet for the client
|
||||
*
|
||||
* @param client
|
||||
* @param sequence
|
||||
* @return
|
||||
*/
|
||||
std::unique_ptr<EQApplicationPacket> CreateServerListPacket(Client *client, uint32 sequence);
|
||||
|
||||
/**
|
||||
* Checks to see if there is a server exists with this name, ignoring option
|
||||
*
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param ignore
|
||||
* @return
|
||||
*/
|
||||
bool ServerExists(std::string server_long_name, std::string server_short_name, WorldServer *ignore = nullptr);
|
||||
|
||||
/**
|
||||
* Destroys a server with this name, ignoring option
|
||||
*
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param ignore
|
||||
*/
|
||||
void DestroyServerByName(std::string server_long_name, std::string server_short_name, WorldServer *ignore = nullptr);
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
const std::list<std::unique_ptr<WorldServer>> &getWorldServers() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> m_server_connection;
|
||||
std::list<std::unique_ptr<WorldServer>> m_world_servers;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -5,9 +5,10 @@
|
||||
#include "../common/net/servertalk_server_connection.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "database.h"
|
||||
#include "../common/event/timer.h"
|
||||
#include "login_types.h"
|
||||
#include "client.h"
|
||||
#include "../common/repositories/login_server_admins_repository.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@ -17,25 +18,10 @@
|
||||
class WorldServer {
|
||||
public:
|
||||
WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> worldserver_connection);
|
||||
|
||||
/**
|
||||
* Destructor, frees our connection if it exists
|
||||
*/
|
||||
~WorldServer();
|
||||
|
||||
/**
|
||||
* Resets the basic stats of this server.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Accesses connection, it is intentional that this is not const (trust me).
|
||||
*/
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> GetConnection() { return m_connection; }
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetServerId() const { return m_server_id; }
|
||||
WorldServer *SetServerId(unsigned int id)
|
||||
{
|
||||
@ -43,25 +29,13 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string GetServerLongName() const { return m_long_name; }
|
||||
std::string GetServerShortName() const { return m_short_name; }
|
||||
|
||||
/**
|
||||
* Gets whether the server is authorized to show up on the server list or not
|
||||
* @return
|
||||
*/
|
||||
bool IsAuthorized() const { return m_is_server_authorized; }
|
||||
std::string GetServerLongName() const { return m_server_long_name; }
|
||||
std::string GetServerShortName() const { return m_server_short_name; }
|
||||
bool IsAuthorizedToList() const { return m_is_server_authorized_to_list; }
|
||||
std::string GetLocalIP() const { return m_local_ip; }
|
||||
std::string GetRemoteIP() const { return m_remote_ip_address; }
|
||||
|
||||
/**
|
||||
* Gets what kind of server this server is (legends, preferred, normal)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
// Gets what kind of server this server is (legends, preferred, normal)
|
||||
unsigned int GetServerListID() const { return m_server_list_type_id; }
|
||||
WorldServer *SetServerListTypeId(unsigned int in_server_list_id);
|
||||
|
||||
@ -69,97 +43,18 @@ public:
|
||||
unsigned int GetZonesBooted() const { return m_zones_booted; }
|
||||
unsigned int GetPlayersOnline() const { return m_players_online; }
|
||||
|
||||
/**
|
||||
* Takes the info struct we received from world and processes it
|
||||
*
|
||||
* @param new_world_server_info_packet
|
||||
*/
|
||||
void Handle_NewLSInfo(ServerNewLSInfo_Struct *new_world_server_info_packet);
|
||||
|
||||
/**
|
||||
* Takes the status struct we received from world and processes it
|
||||
*
|
||||
* @param server_login_status
|
||||
*/
|
||||
void Handle_LSStatus(ServerLSStatus_Struct *server_login_status);
|
||||
|
||||
bool HandleNewLoginserverInfoValidation(ServerNewLSInfo_Struct *new_world_server_info_packet);
|
||||
|
||||
/**
|
||||
* Informs world that there is a client incoming with the following data.
|
||||
*
|
||||
* @param ip
|
||||
* @param account
|
||||
* @param key
|
||||
* @param account_id
|
||||
* @param loginserver_name
|
||||
*/
|
||||
void SendClientAuth(
|
||||
std::string ip,
|
||||
std::string account,
|
||||
std::string key,
|
||||
unsigned int account_id,
|
||||
const std::string &loginserver_name
|
||||
);
|
||||
|
||||
/**
|
||||
* @param world_admin_id
|
||||
* @param world_admin_username
|
||||
* @param world_admin_password
|
||||
* @param world_admin_password_hash
|
||||
* @return
|
||||
*/
|
||||
void HandleNewWorldserver(LoginserverNewWorldRequest *req);
|
||||
void HandleWorldserverStatusUpdate(LoginserverWorldStatusUpdate *u);
|
||||
bool HandleNewWorldserverValidation(LoginserverNewWorldRequest *r);
|
||||
void SendClientAuthToWorld(Client *c);
|
||||
static bool ValidateWorldServerAdminLogin(
|
||||
int world_admin_id,
|
||||
const std::string &world_admin_username,
|
||||
const std::string &world_admin_password,
|
||||
const std::string &world_admin_password_hash
|
||||
LoginWorldAdminAccountContext &c,
|
||||
LoginServerAdminsRepository::LoginServerAdmins &admin
|
||||
);
|
||||
|
||||
WorldServer *SetZonesBooted(unsigned int in_zones_booted);
|
||||
WorldServer *SetPlayersOnline(unsigned int in_players_online);
|
||||
WorldServer *SetServerStatus(int in_server_status);
|
||||
WorldServer *SetServerProcessType(unsigned int in_server_process_type);
|
||||
WorldServer *SetLongName(const std::string &in_long_name);
|
||||
WorldServer *SetShortName(const std::string &in_short_name);
|
||||
WorldServer *SetAccountName(const std::string &in_account_name);
|
||||
WorldServer *SetAccountPassword(const std::string &in_account_password);
|
||||
WorldServer *SetRemoteIp(const std::string &in_remote_ip);
|
||||
WorldServer *SetLocalIp(const std::string &in_local_ip);
|
||||
WorldServer *SetProtocol(const std::string &in_protocol);
|
||||
WorldServer *SetVersion(const std::string &in_version);
|
||||
WorldServer *SetServerDescription(const std::string &in_server_description);
|
||||
WorldServer *SetIsServerAuthorized(bool in_is_server_authorized);
|
||||
WorldServer *SetIsServerLoggedIn(bool in_is_server_logged_in);
|
||||
WorldServer *SetIsServerTrusted(bool in_is_server_trusted);
|
||||
|
||||
bool IsServerAuthorized() const;
|
||||
bool IsServerLoggedIn() const;
|
||||
bool IsServerTrusted() const;
|
||||
const std::string &GetAccountName() const;
|
||||
const std::string &GetAccountPassword() const;
|
||||
const std::string &GetLocalIp() const;
|
||||
const std::string &GetProtocol() const;
|
||||
const std::string &GetRemoteIp() const;
|
||||
const std::string &GetServerDescription() const;
|
||||
const std::string &GetVersion() const;
|
||||
int GetServerStatus() const;
|
||||
unsigned int GetServerListTypeId() const;
|
||||
unsigned int GetServerProcessType() const;
|
||||
|
||||
bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration);
|
||||
bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration);
|
||||
|
||||
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const;
|
||||
void SerializeForClientServerList(class SerializeBuffer &out, bool use_local_ip, LSClientVersion version) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Packet processing functions
|
||||
*
|
||||
* @param opcode
|
||||
* @param packet
|
||||
*/
|
||||
void ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||
void ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||
void ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Net::Packet &packet);
|
||||
@ -175,15 +70,15 @@ private:
|
||||
unsigned int m_server_list_type_id;
|
||||
unsigned int m_server_process_type;
|
||||
std::string m_server_description;
|
||||
std::string m_long_name;
|
||||
std::string m_short_name;
|
||||
std::string m_server_long_name;
|
||||
std::string m_server_short_name;
|
||||
std::string m_account_name;
|
||||
std::string m_account_password;
|
||||
std::string m_remote_ip_address;
|
||||
std::string m_local_ip;
|
||||
std::string m_protocol;
|
||||
std::string m_version;
|
||||
bool m_is_server_authorized;
|
||||
std::string m_server_version;
|
||||
bool m_is_server_authorized_to_list;
|
||||
bool m_is_server_logged_in;
|
||||
bool m_is_server_trusted;
|
||||
|
||||
|
||||
218
loginserver/world_server_manager.cpp
Normal file
218
loginserver/world_server_manager.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
#include "world_server_manager.h"
|
||||
#include "login_server.h"
|
||||
#include "login_types.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/ip_util.h"
|
||||
|
||||
extern LoginServer server;
|
||||
extern bool run_server;
|
||||
|
||||
WorldServerManager::WorldServerManager()
|
||||
{
|
||||
int listen_port = server.config.GetVariableInt("general", "listen_port", 5998);
|
||||
|
||||
m_server_connection = std::make_unique<EQ::Net::ServertalkServer>();
|
||||
EQ::Net::ServertalkServerOptions opts;
|
||||
opts.port = listen_port;
|
||||
opts.ipv6 = false;
|
||||
m_server_connection->Listen(opts);
|
||||
|
||||
LogInfo("Loginserver now listening on port [{}]", listen_port);
|
||||
|
||||
m_server_connection->OnConnectionIdentified(
|
||||
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
|
||||
LogInfo(
|
||||
"New World Server connection from remote_ip [{}] port [{}]",
|
||||
c->Handle()->RemoteIP(),
|
||||
c->Handle()->RemotePort()
|
||||
);
|
||||
|
||||
auto iter = std::find_if(
|
||||
m_world_servers.begin(), m_world_servers.end(),
|
||||
[&](const std::unique_ptr<WorldServer> &s) {
|
||||
return s->GetConnection()->Handle()->RemoteIP() == c->Handle()->RemoteIP() &&
|
||||
s->GetConnection()->Handle()->RemotePort() == c->Handle()->RemotePort();
|
||||
}
|
||||
);
|
||||
|
||||
if (iter != m_world_servers.end()) {
|
||||
LogInfo(
|
||||
"World server already existed for remote_ip [{}] port [{}] removing existing connection.",
|
||||
c->Handle()->RemoteIP(),
|
||||
c->Handle()->RemotePort()
|
||||
);
|
||||
|
||||
m_world_servers.erase(iter);
|
||||
}
|
||||
|
||||
m_world_servers.push_back(std::make_unique<WorldServer>(c));
|
||||
}
|
||||
);
|
||||
|
||||
m_server_connection->OnConnectionRemoved(
|
||||
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
|
||||
auto iter = std::find_if(
|
||||
m_world_servers.begin(), m_world_servers.end(),
|
||||
[&](const std::unique_ptr<WorldServer> &server) {
|
||||
return server->GetConnection()->GetUUID() == c->GetUUID();
|
||||
}
|
||||
);
|
||||
|
||||
if (iter != m_world_servers.end()) {
|
||||
LogInfo(
|
||||
"World server ID [{}] long_name [{}] short_name [{}] has been disconnected, removing.",
|
||||
(*iter)->GetServerId(),
|
||||
(*iter)->GetServerLongName(),
|
||||
(*iter)->GetServerShortName()
|
||||
);
|
||||
m_world_servers.erase(iter);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
WorldServerManager::~WorldServerManager() = default;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> WorldServerManager::CreateServerListPacket(Client *client, uint32 sequence)
|
||||
{
|
||||
unsigned int server_count = 0;
|
||||
in_addr in{};
|
||||
in.s_addr = client->GetConnection()->GetRemoteIP();
|
||||
std::string client_ip = inet_ntoa(in);
|
||||
|
||||
LogDebug("ServerManager::CreateServerListPacket via client address [{}]", client_ip);
|
||||
|
||||
for (const auto &world_server: m_world_servers) {
|
||||
if (world_server->IsAuthorizedToList()) {
|
||||
++server_count;
|
||||
}
|
||||
}
|
||||
|
||||
SerializeBuffer buf;
|
||||
|
||||
// LoginBaseMessage_Struct header
|
||||
buf.WriteInt32(sequence);
|
||||
buf.WriteInt8(0);
|
||||
buf.WriteInt8(0);
|
||||
buf.WriteInt32(0);
|
||||
|
||||
// LoginBaseReplyMessage_Struct
|
||||
buf.WriteInt8(true); // success (no error)
|
||||
buf.WriteInt32(0x65); // 101 "No Error" eqlsstr
|
||||
buf.WriteString("");
|
||||
|
||||
// ServerListReply_Struct
|
||||
buf.WriteInt32(server_count);
|
||||
|
||||
for (const auto &s: m_world_servers) {
|
||||
if (!s->IsAuthorizedToList()) {
|
||||
LogDebug(
|
||||
"ServerManager::CreateServerListPacket | Server [{}] via IP [{}] is not authorized to be listed",
|
||||
s->GetServerLongName(),
|
||||
s->GetConnection()->Handle()->RemoteIP()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool use_local_ip = false;
|
||||
|
||||
std::string world_ip = s->GetConnection()->Handle()->RemoteIP();
|
||||
if (world_ip == client_ip || IpUtil::IsIpInPrivateRfc1918(client_ip)) {
|
||||
use_local_ip = true;
|
||||
}
|
||||
|
||||
LogDebug(
|
||||
"CreateServerListPacket | Building list entry | Client [{}] IP [{}] Server Long Name [{}] Server IP [{}] ({})",
|
||||
client->GetAccountName(),
|
||||
client_ip,
|
||||
s->GetServerLongName(),
|
||||
use_local_ip ? s->GetLocalIP() : s->GetRemoteIP(),
|
||||
use_local_ip ? "Local" : "Remote"
|
||||
);
|
||||
|
||||
s->SerializeForClientServerList(buf, use_local_ip, client->GetClientVersion());
|
||||
}
|
||||
|
||||
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
|
||||
}
|
||||
|
||||
void WorldServerManager::SendUserLoginToWorldRequest(
|
||||
unsigned int server_id,
|
||||
unsigned int client_account_id,
|
||||
const std::string &client_loginserver
|
||||
)
|
||||
{
|
||||
auto iter = std::find_if(
|
||||
m_world_servers.begin(), m_world_servers.end(),
|
||||
[&](const std::unique_ptr<WorldServer> &server) {
|
||||
return server->GetServerId() == server_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (iter != m_world_servers.end()) {
|
||||
EQ::Net::DynamicPacket outapp;
|
||||
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
|
||||
|
||||
auto *r = reinterpret_cast<UsertoWorldRequest_Struct *>(outapp.Data());
|
||||
r->worldid = server_id;
|
||||
r->lsaccountid = client_account_id;
|
||||
strncpy(r->login, client_loginserver.c_str(), 64);
|
||||
|
||||
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp);
|
||||
|
||||
LogNetcode("[UsertoWorldRequest] [Size: {}]\n{}", outapp.Length(), outapp.ToString());
|
||||
}
|
||||
else {
|
||||
LogError("Client requested a user to world but supplied an invalid id of {}", server_id);
|
||||
}
|
||||
}
|
||||
|
||||
bool WorldServerManager::DoesServerExist(
|
||||
const std::string &server_long_name,
|
||||
const std::string &server_short_name,
|
||||
WorldServer *ignore
|
||||
)
|
||||
{
|
||||
return std::any_of(
|
||||
m_world_servers.begin(), m_world_servers.end(), [&](const std::unique_ptr<WorldServer> &s) {
|
||||
return s.get() != ignore &&
|
||||
s->GetServerLongName() == server_long_name &&
|
||||
s->GetServerShortName() == server_short_name;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void WorldServerManager::DestroyServerByName(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
WorldServer *ignore
|
||||
)
|
||||
{
|
||||
std::erase_if(
|
||||
m_world_servers, [&](const std::unique_ptr<WorldServer> &s) {
|
||||
if (s.get() == ignore) {
|
||||
return false;
|
||||
}
|
||||
if (s->GetServerLongName() == server_long_name &&
|
||||
s->GetServerShortName() == server_short_name) {
|
||||
s->GetConnection()->Handle()->Disconnect();
|
||||
LogInfo(
|
||||
"Removing world server ID [{}] long name [{}] short name [{}]",
|
||||
s->GetServerId(),
|
||||
server_long_name,
|
||||
server_short_name
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const std::list<std::unique_ptr<WorldServer>> &WorldServerManager::GetWorldServers() const
|
||||
{
|
||||
return m_world_servers;
|
||||
}
|
||||
33
loginserver/world_server_manager.h
Normal file
33
loginserver/world_server_manager.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef EQEMU_SERVERMANAGER_H
|
||||
#define EQEMU_SERVERMANAGER_H
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "world_server.h"
|
||||
#include "client.h"
|
||||
#include <list>
|
||||
|
||||
class WorldServerManager {
|
||||
public:
|
||||
WorldServerManager();
|
||||
~WorldServerManager();
|
||||
void SendUserLoginToWorldRequest(
|
||||
unsigned int server_id,
|
||||
unsigned int client_account_id,
|
||||
const std::string &client_loginserver
|
||||
);
|
||||
std::unique_ptr<EQApplicationPacket> CreateServerListPacket(Client *client, uint32 sequence);
|
||||
bool DoesServerExist(const std::string &s, const std::string &server_short_name, WorldServer *ignore = nullptr);
|
||||
void DestroyServerByName(std::string s, std::string server_short_name, WorldServer *ignore = nullptr);
|
||||
const std::list<std::unique_ptr<WorldServer>> &GetWorldServers() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> m_server_connection;
|
||||
std::list<std::unique_ptr<WorldServer>> m_world_servers;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -164,9 +164,9 @@ void ClientListEntry::LSUpdate(ZoneServer *iZS)
|
||||
if (WorldConfig::get()->UpdateStats) {
|
||||
auto pack = new ServerPacket;
|
||||
pack->opcode = ServerOP_LSZoneInfo;
|
||||
pack->size = sizeof(ZoneInfo_Struct);
|
||||
pack->size = sizeof(LoginserverZoneInfoUpdate);
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
ZoneInfo_Struct *zone = (ZoneInfo_Struct *) pack->pBuffer;
|
||||
auto *zone = (LoginserverZoneInfoUpdate *) pack->pBuffer;
|
||||
zone->count = iZS->NumPlayers();
|
||||
zone->zone = iZS->GetZoneID();
|
||||
zone->zone_wid = iZS->GetID();
|
||||
@ -174,6 +174,7 @@ void ClientListEntry::LSUpdate(ZoneServer *iZS)
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientListEntry::LSZoneChange(ZoneToZone_Struct *ztz)
|
||||
{
|
||||
if (WorldConfig::get()->UpdateStats) {
|
||||
@ -181,7 +182,7 @@ void ClientListEntry::LSZoneChange(ZoneToZone_Struct *ztz)
|
||||
pack->opcode = ServerOP_LSPlayerZoneChange;
|
||||
pack->size = sizeof(ServerLSPlayerZoneChange_Struct);
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
ServerLSPlayerZoneChange_Struct *zonechange = (ServerLSPlayerZoneChange_Struct *) pack->pBuffer;
|
||||
auto *zonechange = (ServerLSPlayerZoneChange_Struct *) pack->pBuffer;
|
||||
zonechange->lsaccount_id = LSID();
|
||||
zonechange->from = ztz->current_zone_id;
|
||||
zonechange->to = ztz->requested_zone_id;
|
||||
|
||||
@ -1,20 +1,3 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
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; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/global_define.h"
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
@ -37,7 +20,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "cliententry.h"
|
||||
#include "world_config.h"
|
||||
|
||||
|
||||
extern ZSList zoneserver_list;
|
||||
extern ClientList client_list;
|
||||
extern uint32 numzones;
|
||||
@ -609,11 +591,11 @@ void LoginServer::SendInfo()
|
||||
|
||||
auto pack = new ServerPacket;
|
||||
pack->opcode = ServerOP_NewLSInfo;
|
||||
pack->size = sizeof(ServerNewLSInfo_Struct);
|
||||
pack->size = sizeof(LoginserverNewWorldRequest);
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
memset(pack->pBuffer, 0, pack->size);
|
||||
|
||||
auto *l = (ServerNewLSInfo_Struct *) pack->pBuffer;
|
||||
auto *l = (LoginserverNewWorldRequest *) pack->pBuffer;
|
||||
strcpy(l->protocol_version, EQEMU_PROTOCOL_VERSION);
|
||||
strcpy(l->server_version, LOGIN_VERSION);
|
||||
strcpy(l->server_long_name, Config->LongName.c_str());
|
||||
@ -657,10 +639,10 @@ void LoginServer::SendStatus()
|
||||
|
||||
auto pack = new ServerPacket;
|
||||
pack->opcode = ServerOP_LSStatus;
|
||||
pack->size = sizeof(ServerLSStatus_Struct);
|
||||
pack->size = sizeof(LoginserverWorldStatusUpdate);
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
memset(pack->pBuffer, 0, pack->size);
|
||||
auto loginserver_status = (ServerLSStatus_Struct *) pack->pBuffer;
|
||||
auto loginserver_status = (LoginserverWorldStatusUpdate *) pack->pBuffer;
|
||||
|
||||
if (WorldConfig::get()->Locked) {
|
||||
loginserver_status->status = -2;
|
||||
@ -678,9 +660,6 @@ void LoginServer::SendStatus()
|
||||
delete pack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pack
|
||||
*/
|
||||
void LoginServer::SendPacket(ServerPacket *pack)
|
||||
{
|
||||
if (m_legacy_client) {
|
||||
@ -698,15 +677,15 @@ void LoginServer::SendAccountUpdate(ServerPacket *pack)
|
||||
return;
|
||||
}
|
||||
|
||||
auto *ls_account_update = (ServerLSAccountUpdate_Struct *) pack->pBuffer;
|
||||
auto *req = (LoginserverAccountUpdate *) pack->pBuffer;
|
||||
if (CanUpdate()) {
|
||||
LogInfo(
|
||||
"Sending ServerOP_LSAccountUpdate packet to loginserver: [{0}]:[{1}]",
|
||||
m_loginserver_address,
|
||||
m_loginserver_port
|
||||
);
|
||||
strn0cpy(ls_account_update->worldaccount, m_login_account.c_str(), 30);
|
||||
strn0cpy(ls_account_update->worldpassword, m_login_password.c_str(), 30);
|
||||
strn0cpy(req->world_account, m_login_account.c_str(), 30);
|
||||
strn0cpy(req->world_password, m_login_password.c_str(), 30);
|
||||
SendPacket(pack);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,14 +14,14 @@ void SetLoginserverInfo(Client *c, const Seperator *sep)
|
||||
const std::string& email = sep->arg[2];
|
||||
const std::string& password = sep->arg[3];
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_LSAccountUpdate, sizeof(ServerLSAccountUpdate_Struct));
|
||||
auto pack = new ServerPacket(ServerOP_LSAccountUpdate, sizeof(LoginserverAccountUpdate));
|
||||
|
||||
auto s = (ServerLSAccountUpdate_Struct *) pack->pBuffer;
|
||||
auto s = (LoginserverAccountUpdate *) pack->pBuffer;
|
||||
|
||||
s->useraccountid = c->LSAccountID();
|
||||
strn0cpy(s->useraccount, c->AccountName(), 30);
|
||||
s->user_account_id = c->LSAccountID();
|
||||
strn0cpy(s->user_account_name, c->AccountName(), 30);
|
||||
strn0cpy(s->user_email, email.c_str(), 100);
|
||||
strn0cpy(s->userpassword, password.c_str(), 50);
|
||||
strn0cpy(s->user_account_password, password.c_str(), 50);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user