From e901f5e68177e7cf4b3bf3cfaf0cfcdb72344ee3 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Thu, 7 Dec 2023 20:27:46 -0800 Subject: [PATCH] don't save licenses for replay sessions --- src/License.cc | 123 +++++++++++++++++++++++------------------ src/License.hh | 32 +++++++++-- src/ProxyServer.cc | 2 +- src/ReceiveCommands.cc | 22 ++++---- src/ServerShell.cc | 5 +- src/ServerState.cc | 2 +- 6 files changed, 111 insertions(+), 75 deletions(-) diff --git a/src/License.cc b/src/License.cc index 3a8a975a..7b397fa1 100644 --- a/src/License.cc +++ b/src/License.cc @@ -53,17 +53,8 @@ JSON License::json() const { }); } -void License::save() const { - auto json = this->json(); - string json_data = json.serialize(JSON::SerializeOption::FORMAT | JSON::SerializeOption::HEX_INTEGERS); - string filename = string_printf("system/licenses/%010" PRIu32 ".json", this->serial_number); - save_file(filename, json_data); -} - -void License::delete_file() const { - string filename = string_printf("system/licenses/%010" PRIu32 ".json", this->serial_number); - remove(filename.c_str()); -} +void License::save() const {} +void License::delete_file() const {} string License::str() const { vector tokens; @@ -102,53 +93,22 @@ string License::str() const { return "[License: " + join(tokens, ", ") + "]"; } -struct BinaryLicense { - pstring username; // BB username (max. 16 chars; should technically be Unicode) - pstring bb_password; // BB password (max. 16 chars) - uint32_t serial_number; // PC/GC serial number. MUST BE PRESENT FOR BB LICENSES TOO; this is also the player's guild card number. - pstring access_key; // PC/GC access key. (to log in using PC on a GC license, just enter the first 8 characters of the GC access key) - pstring gc_password; // GC password - uint32_t privileges; // privilege level - uint64_t ban_end_time; // end time of ban (zero = not banned) -} __attribute__((packed)); +DiskLicense::DiskLicense(const JSON& json) : License(json) {} -LicenseIndex::LicenseIndex() { - if (!isdir("system/licenses")) { - mkdir("system/licenses", 0755); - } +void DiskLicense::save() const { + auto json = this->json(); + string json_data = json.serialize(JSON::SerializeOption::FORMAT | JSON::SerializeOption::HEX_INTEGERS); + string filename = string_printf("system/licenses/%010" PRIu32 ".json", this->serial_number); + save_file(filename, json_data); +} - // Convert binary licenses to JSON licenses and save them - if (isfile("system/licenses.nsi")) { - auto bin_licenses = load_vector_file("system/licenses.nsi"); - for (const auto& bin_license : bin_licenses) { - // Only add licenses from the binary file if there isn't a JSON version of - // the same license - try { - this->get(bin_license.serial_number); - } catch (const missing_license&) { - License license; - license.serial_number = bin_license.serial_number; - license.access_key = bin_license.access_key.decode(); - license.gc_password = bin_license.gc_password.decode(); - license.bb_username = bin_license.username.decode(); - license.bb_password = bin_license.bb_password.decode(); - license.flags = bin_license.privileges; - license.ban_end_time = bin_license.ban_end_time; - license.ep3_current_meseta = 0; - license.ep3_total_meseta_earned = 0; - license.save(); - } - } - ::remove("system/licenses.nsi"); - } +void DiskLicense::delete_file() const { + string filename = string_printf("system/licenses/%010" PRIu32 ".json", this->serial_number); + remove(filename.c_str()); +} - for (const auto& item : list_directory("system/licenses")) { - if (ends_with(item, ".json")) { - JSON json = JSON::parse(load_file("system/licenses/" + item)); - auto license = make_shared(json); - this->add(license); - } - } +shared_ptr LicenseIndex::create_license() const { + return make_shared(); } size_t LicenseIndex::count() const { @@ -288,3 +248,56 @@ shared_ptr LicenseIndex::verify_bb(const string& username, const string throw missing_license(); } } + +DiskLicenseIndex::DiskLicenseIndex() { + struct BinaryLicense { + pstring username; // BB username (max. 16 chars; should technically be Unicode) + pstring bb_password; // BB password (max. 16 chars) + uint32_t serial_number; // PC/GC serial number. MUST BE PRESENT FOR BB LICENSES TOO; this is also the player's guild card number. + pstring access_key; // PC/GC access key. (to log in using PC on a GC license, just enter the first 8 characters of the GC access key) + pstring gc_password; // GC password + uint32_t privileges; // privilege level + uint64_t ban_end_time; // end time of ban (zero = not banned) + } __attribute__((packed)); + + if (!isdir("system/licenses")) { + mkdir("system/licenses", 0755); + } + + // Convert binary licenses to JSON licenses and save them + if (isfile("system/licenses.nsi")) { + auto bin_licenses = load_vector_file("system/licenses.nsi"); + for (const auto& bin_license : bin_licenses) { + // Only add licenses from the binary file if there isn't a JSON version of + // the same license + try { + this->get(bin_license.serial_number); + } catch (const missing_license&) { + License license; + license.serial_number = bin_license.serial_number; + license.access_key = bin_license.access_key.decode(); + license.gc_password = bin_license.gc_password.decode(); + license.bb_username = bin_license.username.decode(); + license.bb_password = bin_license.bb_password.decode(); + license.flags = bin_license.privileges; + license.ban_end_time = bin_license.ban_end_time; + license.ep3_current_meseta = 0; + license.ep3_total_meseta_earned = 0; + license.save(); + } + } + ::remove("system/licenses.nsi"); + } + + for (const auto& item : list_directory("system/licenses")) { + if (ends_with(item, ".json")) { + JSON json = JSON::parse(load_file("system/licenses/" + item)); + auto license = make_shared(json); + this->add(license); + } + } +} + +shared_ptr DiskLicenseIndex::create_license() const { + return make_shared(); +} diff --git a/src/License.hh b/src/License.hh index 82412bf8..e249671c 100644 --- a/src/License.hh +++ b/src/License.hh @@ -10,7 +10,8 @@ class LicenseIndex; -struct License { +class License { +public: enum Flag : uint32_t { // clang-format off KICK_USER = 0x00000001, @@ -53,14 +54,25 @@ struct License { License() = default; explicit License(const JSON& json); + virtual ~License() = default; JSON json() const; - void save() const; - void delete_file() const; + virtual void save() const; + virtual void delete_file() const; std::string str() const; }; +class DiskLicense : public License { +public: + DiskLicense() = default; + explicit DiskLicense(const JSON& json); + virtual ~DiskLicense() = default; + + virtual void save() const; + virtual void delete_file() const; +}; + class LicenseIndex { public: class no_username : public std::invalid_argument { @@ -80,8 +92,10 @@ public: missing_license() : invalid_argument("missing license") {} }; - LicenseIndex(); - ~LicenseIndex() = default; + LicenseIndex() = default; + virtual ~LicenseIndex() = default; + + virtual std::shared_ptr create_license() const; size_t count() const; std::shared_ptr get(uint32_t serial_number) const; @@ -101,3 +115,11 @@ protected: std::unordered_map> xb_gamertag_to_license; std::unordered_map> serial_number_to_license; }; + +class DiskLicenseIndex : public LicenseIndex { +public: + DiskLicenseIndex(); + virtual ~DiskLicenseIndex() = default; + + virtual std::shared_ptr create_license() const; +}; diff --git a/src/ProxyServer.cc b/src/ProxyServer.cc index e99a2715..2007536e 100644 --- a/src/ProxyServer.cc +++ b/src/ProxyServer.cc @@ -377,7 +377,7 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3 if (!s->allow_unregistered_users) { throw; } - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = fnv1a32(cmd.username.decode()) & 0x7FFFFFFF; l->bb_username = cmd.username.decode(); l->bb_password = cmd.password.decode(); diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 7572403c..13de380d 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -412,7 +412,7 @@ static void on_DB_V3(shared_ptr c, uint16_t, uint32_t, string& data) { c->should_disconnect = true; return; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); l->gc_password = cmd.password.decode(); @@ -456,7 +456,7 @@ static void on_88_DCNTE(shared_ptr c, uint16_t, uint32_t, string& data) send_message_box(c, "Incorrect serial number"); c->should_disconnect = true; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); s->license_index->add(l); @@ -499,7 +499,7 @@ static void on_8B_DCNTE(shared_ptr c, uint16_t, uint32_t, string& data) send_message_box(c, "Incorrect serial number"); c->should_disconnect = true; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); s->license_index->add(l); @@ -553,7 +553,7 @@ static void on_90_DC(shared_ptr c, uint16_t, uint32_t, string& data) { send_command(c, 0x90, 0x03); c->should_disconnect = true; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); s->license_index->add(l); @@ -610,7 +610,7 @@ static void on_93_DC(shared_ptr c, uint16_t, uint32_t, string& data) { c->should_disconnect = true; return; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); s->license_index->add(l); @@ -699,7 +699,7 @@ static void on_9A(shared_ptr c, uint16_t, uint32_t, string& data) { c->should_disconnect = true; return; } else if (is_v1_or_v2(c->version())) { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); s->license_index->add(l); @@ -759,7 +759,7 @@ static void on_9C(shared_ptr c, uint16_t, uint32_t, string& data) { c->should_disconnect = true; return; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = cmd.access_key.decode(); if (is_gc(c->version())) { @@ -878,7 +878,7 @@ static void on_9D_9E(shared_ptr c, uint16_t command, uint32_t, string& d c->should_disconnect = true; return; } else if (is_v1_or_v2(c->version())) { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = serial_number; l->access_key = base_cmd->access_key.decode(); s->license_index->add(l); @@ -947,7 +947,7 @@ static void on_9E_XB(shared_ptr c, uint16_t, uint32_t, string& data) { return; } catch (const LicenseIndex::missing_license& e) { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = fnv1a32(xb_gamertag) & 0x7FFFFFFF; l->xb_gamertag = xb_gamertag; l->xb_user_id = xb_user_id; @@ -1004,7 +1004,7 @@ static void on_93_BB(shared_ptr c, uint16_t, uint32_t, string& data) { c->should_disconnect = true; return; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = fnv1a32(cmd.username.decode()) & 0x7FFFFFFF; l->bb_username = cmd.username.decode(); l->bb_password = cmd.password.decode(); @@ -4893,7 +4893,7 @@ static void on_04_P(shared_ptr c, uint16_t, uint32_t, string& data) { return; } else { - auto l = make_shared(); + auto l = s->license_index->create_license(); l->serial_number = fnv1a32(cmd.username.decode()) & 0x7FFFFFFF; l->bb_username = cmd.username.decode(); l->bb_password = cmd.password.decode(); diff --git a/src/ServerShell.cc b/src/ServerShell.cc index 2f53e57b..df8cff1b 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -321,7 +321,7 @@ Proxy session commands:\n\ } } else if (command_name == "add-license") { - auto l = make_shared(); + auto l = this->state->license_index->create_license(); for (const string& token : split(command_args, ' ')) { if (starts_with(token, "bb-username=")) { @@ -376,7 +376,8 @@ Proxy session commands:\n\ uint32_t serial_number = stoul(tokens[0]); tokens.erase(tokens.begin()); auto orig_l = this->state->license_index->get(serial_number); - auto l = make_shared(*orig_l); + auto l = this->state->license_index->create_license(); + *l = *orig_l; this->state->license_index->remove(orig_l->serial_number); try { diff --git a/src/ServerState.cc b/src/ServerState.cc index c55bcef7..cb9e8a85 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -973,7 +973,7 @@ void ServerState::load_bb_private_keys() { void ServerState::load_licenses() { config_log.info("Indexing licenses"); - this->license_index = make_shared(); + this->license_index = this->is_replay ? make_shared() : make_shared(); } void ServerState::load_teams() {