From c5cac171250d8ad14637eda25e8b878108a1313a Mon Sep 17 00:00:00 2001 From: server Date: Tue, 14 Apr 2026 10:58:11 +0200 Subject: [PATCH] game: prepare auth login query --- src/game/db.cpp | 225 ++++++++++++++++++++++++++++++++++++++++ src/game/db.h | 1 + src/game/input_auth.cpp | 52 +--------- 3 files changed, 227 insertions(+), 51 deletions(-) diff --git a/src/game/db.cpp b/src/game/db.cpp index 75757d6..2a23536 100644 --- a/src/game/db.cpp +++ b/src/game/db.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include #include #include "common/length.h" @@ -17,9 +18,211 @@ #include "login_data.h" #include "locale_service.h" #include "spam.h" +#include "libsql/Statement.h" extern std::string g_stBlockDate; +namespace +{ +struct AuthLoginData +{ + char encryptedPassword[45 + 1] = {}; + char password[45 + 1] = {}; + char socialId[SOCIAL_ID_MAX_LEN + 1] = {}; + char status[ACCOUNT_STATUS_MAX_LEN + 1] = {}; + uint32_t accountId = 0; + uint8_t notAvailable = 0; + std::array premiumTimes = {}; + long long createTime = 0; +}; + +bool IsChannelServiceLogin(const char* login) +{ + return login && login[0] == '['; +} + +bool PrepareGameStmt(CStmt& stmt, const std::string& query) +{ + CAsyncSQL* sql = DBManager::instance().GetDirectSQL(); + + if (!sql) + { + sys_err("game direct SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); +} + +bool LoadAuthLoginData(const char* login, const char* passwd, AuthLoginData& auth, bool& found) +{ + CStmt stmt; + const bool channelServiceLogin = IsChannelServiceLogin(login); + const std::string query = channelServiceLogin + ? "SELECT ?, password, social_id, id, status, availDt - NOW() > 0," + "UNIX_TIMESTAMP(silver_expire)," + "UNIX_TIMESTAMP(gold_expire)," + "UNIX_TIMESTAMP(safebox_expire)," + "UNIX_TIMESTAMP(autoloot_expire)," + "UNIX_TIMESTAMP(fish_mind_expire)," + "UNIX_TIMESTAMP(marriage_fast_expire)," + "UNIX_TIMESTAMP(money_drop_rate_expire)," + "UNIX_TIMESTAMP(create_time)" + " FROM account WHERE login=?" + : "SELECT PASSWORD(?), password, social_id, id, status, availDt - NOW() > 0," + "UNIX_TIMESTAMP(silver_expire)," + "UNIX_TIMESTAMP(gold_expire)," + "UNIX_TIMESTAMP(safebox_expire)," + "UNIX_TIMESTAMP(autoloot_expire)," + "UNIX_TIMESTAMP(fish_mind_expire)," + "UNIX_TIMESTAMP(marriage_fast_expire)," + "UNIX_TIMESTAMP(money_drop_rate_expire)," + "UNIX_TIMESTAMP(create_time)" + " FROM account WHERE login=?"; + + found = false; + + if (!PrepareGameStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_STRING, const_cast(passwd)) + || !stmt.BindParam(MYSQL_TYPE_STRING, const_cast(login))) + { + return false; + } + + if (!stmt.BindResult(MYSQL_TYPE_STRING, auth.encryptedPassword, sizeof(auth.encryptedPassword)) + || !stmt.BindResult(MYSQL_TYPE_STRING, auth.password, sizeof(auth.password)) + || !stmt.BindResult(MYSQL_TYPE_STRING, auth.socialId, sizeof(auth.socialId)) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.accountId) + || !stmt.BindResult(MYSQL_TYPE_STRING, auth.status, sizeof(auth.status)) + || !stmt.BindResult(MYSQL_TYPE_TINY, &auth.notAvailable) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_EXP]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_ITEM]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_SAFEBOX]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_AUTOLOOT]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_FISH_MIND]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_MARRIAGE_FAST]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &auth.premiumTimes[PREMIUM_GOLD]) + || !stmt.BindResult(MYSQL_TYPE_LONGLONG, &auth.createTime)) + { + return false; + } + + if (!stmt.Execute()) + return false; + + if (stmt.iRows == 0) + return true; + + if (!stmt.Fetch()) + return false; + + found = true; + return true; +} + +void FormatCreateDate(const AuthLoginData& auth, char* dst, size_t dstSize) +{ + strlcpy(dst, "00000000", dstSize); + + if (auth.createTime <= 0) + return; + + time_t createTime = static_cast(auth.createTime); + struct tm tmBuf; + + if (!localtime_r(&createTime, &tmBuf)) + return; + + strftime(dst, dstSize, "%Y%m%d", &tmBuf); +} + +void UpdateAccountLastPlay(uint32_t accountId) +{ + CStmt stmt; + const std::string query = "UPDATE account SET last_play=NOW() WHERE id=?"; + + if (!PrepareGameStmt(stmt, query)) + return; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &accountId)) + return; + + if (!stmt.Execute()) + { + sys_err("failed to update last_play for account %u", accountId); + } +} + +void FinalizeAuthLogin(LPDESC d, const char* login, const char* passwd, const AuthLoginData& auth, const char* logPrefix) +{ + char createDate[256] = "00000000"; + + if (LC_IsEurope() || test_server) + { + FormatCreateDate(auth, createDate, sizeof(createDate)); + sys_log(0, "Create_Time %lld %s", auth.createTime, createDate); + sys_log(0, "Block Time %d ", strncmp(createDate, g_stBlockDate.c_str(), 8)); + } + + if (strcmp(auth.encryptedPassword, auth.password)) + { + RecordLoginFailure(d->GetHostName()); + LoginFailure(d, "WRONGPWD"); + sys_log(0, " WRONGPWD"); + return; + } + + if (auth.notAvailable) + { + LoginFailure(d, "NOTAVAIL"); + sys_log(0, " NOTAVAIL"); + return; + } + + if (DESC_MANAGER::instance().FindByLoginName(login)) + { + LoginFailure(d, "ALREADY"); + sys_log(0, " ALREADY"); + return; + } + + if (strcmp(auth.status, "OK")) + { + LoginFailure(d, auth.status); + sys_log(0, " STATUS: %s", auth.status); + return; + } + + if (LC_IsEurope()) + { + if (strncmp(createDate, g_stBlockDate.c_str(), 8) >= 0) + { + LoginFailure(d, "BLKLOGIN"); + sys_log(0, " BLKLOGIN"); + return; + } + + UpdateAccountLastPlay(auth.accountId); + } + + TAccountTable& r = d->GetAccountTable(); + int premiumTimes[PREMIUM_MAX_NUM]; + + r.id = auth.accountId; + trim_and_lower(login, r.login, sizeof(r.login)); + strlcpy(r.passwd, passwd, sizeof(r.passwd)); + strlcpy(r.social_id, auth.socialId, sizeof(r.social_id)); + DESC_MANAGER::instance().ConnectAccount(r.login, d); + ClearLoginFailure(d->GetHostName()); + + thecore_memcpy(premiumTimes, auth.premiumTimes.data(), sizeof(premiumTimes)); + DBManager::instance().LoginPrepare(d, premiumTimes); + sys_log(0, "%s: SUCCESS %s", logPrefix, login); +} +} + DBManager::DBManager() : m_bIsConnect(false) { } @@ -232,6 +435,28 @@ void DBManager::LoginPrepare(LPDESC d, int * paiPremiumTimes) SendAuthLogin(d); } +void DBManager::AuthenticateLogin(LPDESC d, const char* login, const char* passwd) +{ + AuthLoginData auth; + bool found = false; + + d->SetLogin(login); + sys_log(0, "AUTH_LOGIN_DIRECT: START %u %p", d->GetLoginKey(), get_pointer(d)); + + if (IsChannelServiceLogin(login)) + sys_log(0, "ChannelServiceLogin [%s]", login); + + if (!LoadAuthLoginData(login, passwd, auth, found) || !found) + { + sys_log(0, " NOID"); + RecordLoginFailure(d->GetHostName()); + LoginFailure(d, "NOID"); + return; + } + + FinalizeAuthLogin(d, login, passwd, auth, "AUTH_LOGIN_DIRECT"); +} + void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg) { CReturnQueryInfo * qi = (CReturnQueryInfo *) pMsg->pvUserData; diff --git a/src/game/db.h b/src/game/db.h index b716ab3..810c245 100644 --- a/src/game/db.h +++ b/src/game/db.h @@ -82,6 +82,7 @@ class DBManager : public singleton void SendMoneyLog(BYTE type, DWORD vnum, int gold); void LoginPrepare(LPDESC d, int * paiPremiumTimes = NULL); + void AuthenticateLogin(LPDESC d, const char* login, const char* passwd); void SendAuthLogin(LPDESC d); void SendLoginPing(const char * c_pszLogin); diff --git a/src/game/input_auth.cpp b/src/game/input_auth.cpp index 6a2bb98..d22af50 100644 --- a/src/game/input_auth.cpp +++ b/src/game/input_auth.cpp @@ -141,13 +141,6 @@ bool FN_IS_VALID_LOGIN_STRING(const char *str) return true; } -bool Login_IsInChannelService(const char* c_login) -{ - if (c_login[0] == '[') - return true; - return false; -} - CInputAuth::CInputAuth() { RegisterHandlers(); @@ -233,50 +226,7 @@ void CInputAuth::Login(LPDESC d, const char * c_pData) sys_log(0, "InputAuth::Login : key %u login %s", dwKey, login); - TPacketCGLogin3 * p = M2_NEW TPacketCGLogin3; - thecore_memcpy(p, pinfo, sizeof(TPacketCGLogin3)); - - char szPasswd[PASSWD_MAX_LEN * 2 + 1]; - DBManager::instance().EscapeString(szPasswd, sizeof(szPasswd), passwd, strlen(passwd)); - - char szLogin[LOGIN_MAX_LEN * 2 + 1]; - DBManager::instance().EscapeString(szLogin, sizeof(szLogin), login, strlen(login)); - - // CHANNEL_SERVICE_LOGIN - if (Login_IsInChannelService(szLogin)) - { - sys_log(0, "ChannelServiceLogin [%s]", szLogin); - - DBManager::instance().ReturnQuery(QID_AUTH_LOGIN, dwKey, p, - "SELECT '%s',password,social_id,id,status,availDt - NOW() > 0," - "UNIX_TIMESTAMP(silver_expire)," - "UNIX_TIMESTAMP(gold_expire)," - "UNIX_TIMESTAMP(safebox_expire)," - "UNIX_TIMESTAMP(autoloot_expire)," - "UNIX_TIMESTAMP(fish_mind_expire)," - "UNIX_TIMESTAMP(marriage_fast_expire)," - "UNIX_TIMESTAMP(money_drop_rate_expire)," - "UNIX_TIMESTAMP(create_time)" - " FROM account WHERE login='%s'", - - szPasswd, szLogin); - } - // END_OF_CHANNEL_SERVICE_LOGIN - else - { - DBManager::instance().ReturnQuery(QID_AUTH_LOGIN, dwKey, p, - "SELECT PASSWORD('%s'),password,social_id,id,status,availDt - NOW() > 0," - "UNIX_TIMESTAMP(silver_expire)," - "UNIX_TIMESTAMP(gold_expire)," - "UNIX_TIMESTAMP(safebox_expire)," - "UNIX_TIMESTAMP(autoloot_expire)," - "UNIX_TIMESTAMP(fish_mind_expire)," - "UNIX_TIMESTAMP(marriage_fast_expire)," - "UNIX_TIMESTAMP(money_drop_rate_expire)," - "UNIX_TIMESTAMP(create_time)" - " FROM account WHERE login='%s'", - szPasswd, szLogin); - } + DBManager::instance().AuthenticateLogin(d, login, passwd); } int CInputAuth::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData)