Add login lock session plumbing
This commit is contained in:
@@ -170,6 +170,59 @@ void configure_from_json(const phosg::JSON& json) {
|
||||
configure(cfg);
|
||||
}
|
||||
|
||||
asio::awaitable<LoginLockAcquireResult> acquire_login_lock(
|
||||
uint32_t account_id,
|
||||
const std::string& version_name,
|
||||
const std::string& existing_session_nonce) {
|
||||
auto cfg = get_config();
|
||||
|
||||
LoginLockAcquireResult ret;
|
||||
if (!cfg.enabled || !cfg.enable_login_locks) {
|
||||
co_return ret;
|
||||
}
|
||||
|
||||
if (!existing_session_nonce.empty()) {
|
||||
ret.session_nonce = existing_session_nonce;
|
||||
co_return ret;
|
||||
}
|
||||
|
||||
ret.session_nonce = std::format("{}-{}-{}", source_label(cfg), account_id, now_usecs());
|
||||
std::fprintf(stderr,
|
||||
"[AccountSync] warning login_locks enabled but coordinator acquire is not implemented; allowing account_id=%010u source=%s version=%s nonce=%s\n",
|
||||
static_cast<unsigned int>(account_id),
|
||||
source_label(cfg).c_str(),
|
||||
version_name.c_str(),
|
||||
ret.session_nonce.c_str());
|
||||
|
||||
co_return ret;
|
||||
}
|
||||
|
||||
void notify_login_session_end(
|
||||
uint32_t account_id,
|
||||
const std::string& session_nonce,
|
||||
const std::string& version_name) {
|
||||
auto cfg = get_config();
|
||||
if (!cfg.enabled || !cfg.enable_login_locks) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::fprintf(stderr,
|
||||
"[AccountSync] event=login_session_end source=%s source_region=%s source_ship=%s account_store=%s account_id=%010u session_nonce=%s version=%s\n",
|
||||
source_label(cfg).c_str(),
|
||||
cfg.source_region.c_str(),
|
||||
cfg.source_ship.c_str(),
|
||||
cfg.account_store.c_str(),
|
||||
static_cast<unsigned int>(account_id),
|
||||
session_nonce.c_str(),
|
||||
version_name.c_str());
|
||||
|
||||
auto line = base_event_json(cfg, "login_session_end", account_id) +
|
||||
std::format(",\"session_nonce\":\"{}\",\"version\":\"{}\"}}",
|
||||
json_escape(session_nonce),
|
||||
json_escape(version_name));
|
||||
append_spool_line(cfg, line);
|
||||
}
|
||||
|
||||
void notify_account_saved(uint32_t account_id, const std::string& filename) {
|
||||
auto cfg = get_config();
|
||||
if (!cfg.enabled || !cfg.notify_account_saves) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <phosg/JSON.hh>
|
||||
@@ -33,6 +35,24 @@ struct Config {
|
||||
void configure(const Config& cfg);
|
||||
void configure_from_json(const phosg::JSON& json);
|
||||
|
||||
struct LoginLockAcquireResult {
|
||||
bool allowed = true;
|
||||
bool fail_open_used = false;
|
||||
std::string session_nonce;
|
||||
std::string message;
|
||||
std::string holder_source;
|
||||
};
|
||||
|
||||
asio::awaitable<LoginLockAcquireResult> acquire_login_lock(
|
||||
uint32_t account_id,
|
||||
const std::string& version_name,
|
||||
const std::string& existing_session_nonce);
|
||||
|
||||
void notify_login_session_end(
|
||||
uint32_t account_id,
|
||||
const std::string& session_nonce,
|
||||
const std::string& version_name);
|
||||
|
||||
void notify_account_saved(uint32_t account_id, const std::string& filename);
|
||||
void notify_backup_saved(uint32_t account_id, size_t slot, const std::string& filename);
|
||||
|
||||
|
||||
@@ -278,6 +278,15 @@ Client::~Client() {
|
||||
this->bb_character_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->account_sync_lock_acquired && this->login && this->login->account) {
|
||||
AccountSync::notify_login_session_end(
|
||||
this->login->account->account_id,
|
||||
this->account_sync_session_nonce,
|
||||
phosg::name_for_enum(this->version()));
|
||||
this->account_sync_lock_acquired = false;
|
||||
}
|
||||
|
||||
this->log.info_f("Deleted");
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,9 @@ public:
|
||||
uint64_t xb_user_id = 0;
|
||||
uint32_t xb_unknown_a1b = 0;
|
||||
std::shared_ptr<Login> login;
|
||||
bool account_sync_lock_acquired = false;
|
||||
uint32_t account_sync_lock_account_id = 0;
|
||||
std::string account_sync_session_nonce;
|
||||
std::shared_ptr<ProxySession> proxy_session;
|
||||
|
||||
// Patch server state (only used for PC_PATCH and BB_PATCH versions)
|
||||
|
||||
@@ -558,6 +558,25 @@ asio::awaitable<void> start_login_server_procedure(std::shared_ptr<Client> c) {
|
||||
static asio::awaitable<void> on_login_complete(std::shared_ptr<Client> c) {
|
||||
auto s = c->require_server_state();
|
||||
|
||||
if (c->login && c->login->account) {
|
||||
auto lock_res = co_await AccountSync::acquire_login_lock(
|
||||
c->login->account->account_id,
|
||||
phosg::name_for_enum(c->version()),
|
||||
c->account_sync_session_nonce);
|
||||
|
||||
if (!lock_res.allowed) {
|
||||
c->log.info_f("Login lock denied: {}", lock_res.message);
|
||||
c->channel->disconnect();
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (!lock_res.session_nonce.empty()) {
|
||||
c->account_sync_lock_acquired = true;
|
||||
c->account_sync_lock_account_id = c->login->account->account_id;
|
||||
c->account_sync_session_nonce = lock_res.session_nonce;
|
||||
}
|
||||
}
|
||||
|
||||
c->convert_account_to_temporary_if_nte();
|
||||
|
||||
if (!is_v4(c->version())) {
|
||||
|
||||
Reference in New Issue
Block a user