add option to use temporary licenses for NTE versions

This commit is contained in:
Martin Michelsen
2023-12-30 11:30:43 -08:00
parent c1ac34c1f7
commit e89802f288
15 changed files with 107 additions and 73 deletions
+29
View File
@@ -135,6 +135,18 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
}
}
bool Client::Config::should_update_vs(const Config& other) const {
constexpr uint64_t mask = static_cast<uint64_t>(Flag::CLIENT_SIDE_MASK);
return ((this->enabled_flags ^ other.enabled_flags) & mask) ||
(this->specific_version != other.specific_version) ||
(this->override_random_seed != other.override_random_seed) ||
(this->override_section_id != other.override_section_id) ||
(this->override_lobby_event != other.override_lobby_event) ||
(this->override_lobby_number != other.override_lobby_number) ||
(this->proxy_destination_address != other.proxy_destination_address) ||
(this->proxy_destination_port != other.proxy_destination_port);
}
Client::Client(
shared_ptr<Server> server,
struct bufferevent* bev,
@@ -243,6 +255,23 @@ void Client::set_license(shared_ptr<License> l) {
this->license = l;
}
void Client::convert_license_to_temporary_if_nte() {
// If the session is a prototype version and the license was created and we
// should use a temporary license instead, delete the permanent license and
// replace it with a temporary license.
auto s = this->require_server_state();
if (s->use_temp_licenses_for_prototypes &&
this->config.check_flag(Client::Flag::LICENSE_WAS_CREATED) &&
is_any_nte(this->version())) {
this->log.info("Client is a prototype version and the license was created during this session; converting permanent license to temporary license");
s->license_index->remove(this->license->serial_number);
auto new_l = s->license_index->create_temporary_license();
this->license->delete_file();
*new_l = std::move(*this->license);
this->set_license(new_l);
}
}
shared_ptr<ServerState> Client::require_server_state() const {
auto server = this->server.lock();
if (!server) {
+20 -10
View File
@@ -30,8 +30,15 @@ public:
enum class Flag : uint64_t {
// clang-format off
// This mask specifies which flags are sent to the client
// TODO: It'd be nice to use a pattern here (e.g. all server-side flags are
// in the high bits) but that would require re-recording or manually
// rewriting all the tests
CLIENT_SIDE_MASK = 0xFFFFFFFFFC0FFFFB,
// Version-related flags
CHECKED_FOR_DC_V1_PROTOTYPE = 0x0000000000000002,
LICENSE_WAS_CREATED = 0x0000000000000004, // Server-side only
NO_D6_AFTER_LOBBY = 0x0000000000000100,
NO_D6 = 0x0000000000000200,
FORCE_ENGLISH_LANGUAGE_BB = 0x0000000000000400,
@@ -44,20 +51,20 @@ public:
USE_OVERFLOW_FOR_SEND_FUNCTION_CALL = 0x0000000000010000,
// State flags
LOADING = 0x0000000000100000,
LOADING_QUEST = 0x0000000000200000,
LOADING_RUNNING_JOINABLE_QUEST = 0x0000000000400000,
LOADING_TOURNAMENT = 0x0000000000800000,
IN_INFORMATION_MENU = 0x0000000001000000,
AT_WELCOME_MESSAGE = 0x0000000002000000,
LOADING = 0x0000000000100000, // Server-side only
LOADING_QUEST = 0x0000000000200000, // Server-side only
LOADING_RUNNING_JOINABLE_QUEST = 0x0000000000400000, // Server-side only
LOADING_TOURNAMENT = 0x0000000000800000, // Server-side only
IN_INFORMATION_MENU = 0x0000000001000000, // Server-side only
AT_WELCOME_MESSAGE = 0x0000000002000000, // Server-side only
SAVE_ENABLED = 0x0000000004000000,
HAS_EP3_CARD_DEFS = 0x0000000008000000,
HAS_EP3_MEDIA_UPDATES = 0x0000000010000000,
USE_OVERRIDE_RANDOM_SEED = 0x0000000020000000,
HAS_GUILD_CARD_NUMBER = 0x0000000040000000,
AT_BANK_COUNTER = 0x0000000080000000,
SHOULD_SEND_ARTIFICIAL_ITEM_STATE = 0x0001000000000000,
SHOULD_SEND_ARTIFICIAL_FLAG_STATE = 0x0002000000000000,
AT_BANK_COUNTER = 0x0000000080000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_ITEM_STATE = 0x0001000000000000, // Server-side only
SHOULD_SEND_ARTIFICIAL_FLAG_STATE = 0x0002000000000000, // Server-side only
SHOULD_SEND_ENABLE_SAVE = 0x0004000000000000,
SWITCH_ASSIST_ENABLED = 0x0000000100000000,
@@ -99,6 +106,8 @@ public:
bool operator==(const Config& other) const = default;
bool operator!=(const Config& other) const = default;
bool should_update_vs(const Config& other) const;
[[nodiscard]] static inline bool check_flag(uint64_t enabled_flags, Flag flag) {
return !!(enabled_flags & static_cast<uint64_t>(flag));
}
@@ -139,7 +148,7 @@ public:
StringWriter w;
w.put_u32l(CLIENT_CONFIG_MAGIC);
w.put_u32l(this->specific_version);
w.put_u64l(this->enabled_flags);
w.put_u64l(this->enabled_flags & static_cast<uint64_t>(Flag::CLIENT_SIDE_MASK));
w.put_u32l(this->override_random_seed);
w.put_u32b(this->proxy_destination_address);
w.put_u16l(this->proxy_destination_port);
@@ -263,6 +272,7 @@ public:
}
void set_license(std::shared_ptr<License> l);
void convert_license_to_temporary_if_nte();
void sync_config();
+16 -7
View File
@@ -257,6 +257,8 @@ static void send_main_menu(shared_ptr<Client> c) {
}
void on_login_complete(shared_ptr<Client> c) {
c->convert_license_to_temporary_if_nte();
// On BB, this function is called when the data server phase is done (and we
// should send the ship select menu), so we don't need to check for it here.
switch (c->server_behavior) {
@@ -428,6 +430,7 @@ static void on_DB_V3(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->should_disconnect = true;
return;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -472,6 +475,7 @@ static void on_88_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
send_message_box(c, "Incorrect serial number");
c->should_disconnect = true;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -515,6 +519,7 @@ static void on_8B_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
send_message_box(c, "Incorrect serial number");
c->should_disconnect = true;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -569,6 +574,7 @@ static void on_90_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
send_command(c, 0x90, 0x03);
c->should_disconnect = true;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -626,6 +632,7 @@ static void on_93_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->should_disconnect = true;
return;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -743,6 +750,7 @@ static void on_9A(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->should_disconnect = true;
} else if (is_v1_or_v2(c->version())) {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -805,6 +813,7 @@ static void on_9C(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->should_disconnect = true;
return;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = cmd.access_key.decode();
@@ -942,16 +951,13 @@ static void on_9D_9E(shared_ptr<Client> c, uint16_t command, uint32_t, string& d
return;
} catch (const LicenseIndex::missing_license& e) {
// On GC, the client should have sent a different command containing the
// password already, which should have created and added a license. So, if
// no license exists at this point, disconnect the client even if
// unregistered clients are allowed.
if (is_v3(c->version()) || !s->allow_unregistered_users || (serial_number == 0)) {
if (!s->allow_unregistered_users || (serial_number == 0)) {
send_command(c, 0x04, 0x04);
c->should_disconnect = true;
return;
} else if (is_v1_or_v2(c->version())) {
} else if (is_v1_or_v2(c->version()) || is_v3(c->version())) {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = serial_number;
l->access_key = base_cmd->access_key.decode();
@@ -1022,6 +1028,7 @@ static void on_9E_XB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
return;
} catch (const LicenseIndex::missing_license& e) {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = fnv1a32(xb_gamertag) & 0x7FFFFFFF;
l->xb_gamertag = xb_gamertag;
@@ -1113,6 +1120,7 @@ static void on_93_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->should_disconnect = true;
return;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = fnv1a32(username) & 0x7FFFFFFF;
l->bb_username = username;
@@ -3034,6 +3042,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
if (c->config.specific_version == 0x33000000) {
c->config.specific_version = 0x33534A54; // 3SJT
}
c->convert_license_to_temporary_if_nte();
}
cmd = &check_size_t<C_CharacterData_V3_61_98>(data, 0xFFFF);
}
@@ -5071,7 +5080,7 @@ static void on_04_P(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->should_disconnect = true;
return;
} else {
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
auto l = s->license_index->create_license();
l->serial_number = fnv1a32(cmd.username.decode()) & 0x7FFFFFFF;
l->bb_username = cmd.username.decode();
+1 -1
View File
@@ -282,7 +282,7 @@ void send_server_init(shared_ptr<Client> c, uint8_t flags) {
}
void send_update_client_config(shared_ptr<Client> c, bool always_send) {
if (always_send || (is_v3(c->version()) && (c->config != c->synced_config))) {
if (always_send || (is_v3(c->version()) && (c->config.should_update_vs(c->synced_config)))) {
switch (c->version()) {
case Version::DC_NTE:
case Version::DC_V1_11_2000_PROTOTYPE:
+2
View File
@@ -39,6 +39,7 @@ ServerState::ServerState(shared_ptr<struct event_base> base, const string& confi
ip_stack_debug(false),
allow_unregistered_users(false),
allow_pc_nte(false),
use_temp_licenses_for_prototypes(true),
allow_dc_pc_games(false),
allow_gc_xb_games(true),
allowed_drop_modes_v1_v2_normal(0x1F),
@@ -669,6 +670,7 @@ void ServerState::parse_config(const JSON& json, bool is_reload) {
this->ip_stack_debug = json.get_bool("IPStackDebug", this->ip_stack_debug);
this->allow_unregistered_users = json.get_bool("AllowUnregisteredUsers", this->allow_unregistered_users);
this->allow_pc_nte = json.get_bool("AllowPCNTE", this->allow_pc_nte);
this->use_temp_licenses_for_prototypes = json.get_bool("UseTemporaryLicensesForPrototypes", this->use_temp_licenses_for_prototypes);
this->allowed_drop_modes_v1_v2_normal = json.get_int("AllowedDropModesV1V2Normal", this->allowed_drop_modes_v1_v2_normal);
this->allowed_drop_modes_v1_v2_battle = json.get_int("AllowedDropModesV1V2Battle", this->allowed_drop_modes_v1_v2_battle);
this->allowed_drop_modes_v1_v2_challenge = json.get_int("AllowedDropModesV1V2Challenge", this->allowed_drop_modes_v1_v2_challenge);
+1
View File
@@ -75,6 +75,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
bool ip_stack_debug;
bool allow_unregistered_users;
bool allow_pc_nte;
bool use_temp_licenses_for_prototypes;
bool allow_dc_pc_games;
bool allow_gc_xb_games;
uint8_t allowed_drop_modes_v1_v2_normal;
+8
View File
@@ -29,6 +29,14 @@ const char* name_for_enum<Version>(Version v);
template <>
Version enum_for_name<Version>(const char* name);
inline bool is_any_nte(Version version) {
return (version == Version::DC_NTE) ||
(version == Version::DC_V1_11_2000_PROTOTYPE) ||
(version == Version::PC_NTE) ||
(version == Version::GC_NTE) ||
(version == Version::GC_EP3_NTE);
}
inline bool is_patch(Version version) {
return (version == Version::PC_PATCH) || (version == Version::BB_PATCH);
}