diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index c9af59a014..f9f7206d12 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -4170,6 +4170,8 @@ STR_5858 :{SMALLFONT}{BLACK}Use GPU for displaying instead of CPU. Improves c STR_5859 :{SMALLFONT}{BLACK}Enables frame tweening for visually{NEWLINE}smoother gameplay. When disabled,{NEWLINE}the game will run at 40 FPS. STR_5860 :Toggle original/decompiled track drawing STR_5861 :Key verification failure. +STR_5862 :Allow joining with known keys only. +STR_5863 :This host only allows known keys to connect. ############# # Scenarios # diff --git a/src/config.c b/src/config.c index cc54cacdd2..96414ed507 100644 --- a/src/config.c +++ b/src/config.c @@ -252,7 +252,8 @@ config_property_definition _networkDefinitions[] = { { offsetof(network_configuration, master_server_url), "master_server_url", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, { offsetof(network_configuration, provider_name), "provider_name", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, { offsetof(network_configuration, provider_email), "provider_email", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, provider_website), "provider_website", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL } + { offsetof(network_configuration, provider_website), "provider_website", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, + { offsetof(network_configuration, known_keys_only), "known_keys_only", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, }; config_property_definition _notificationsDefinitions[] = { diff --git a/src/config.h b/src/config.h index ee2cffd489..bbdccebe22 100644 --- a/src/config.h +++ b/src/config.h @@ -229,6 +229,7 @@ typedef struct network_configuration { utf8string provider_name; utf8string provider_email; utf8string provider_website; + uint8 known_keys_only; } network_configuration; typedef struct notification_configuration { diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index e130908af0..29c24c3e3b 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -2634,6 +2634,8 @@ enum { STR_TRACK_PREVIEW_NAME_FORMAT = 5814, STR_MULTIPLAYER_VERIFICATION_FAILURE = 5861, + STR_ALLOW_KNOWN_KEYS_ONLY = 5862, + STR_MULTIPLAYER_UNKNOWN_KEY_DISALLOWED = 5863, // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 diff --git a/src/network/network.cpp b/src/network/network.cpp index d5be31562d..248e4d6e07 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -2110,6 +2110,10 @@ void Network::Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p case NETWORK_AUTH_REQUIREPASSWORD: window_network_status_open_password(); break; + case NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED: + connection.setLastDisconnectReason(STR_MULTIPLAYER_UNKNOWN_KEY_DISALLOWED); + shutdown(connection.socket, SHUT_RDWR); + break; } } @@ -2156,14 +2160,17 @@ void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p connection.key.LoadPublic(pubkey_rw); SDL_RWclose(pubkey_rw); bool verified = connection.key.Verify(connection.challenge.data(), connection.challenge.size(), signature, sigsize); + const std::string hash = connection.key.PublicKeyHash(); if (verified) { connection.authstatus = NETWORK_AUTH_VERIFIED; - const std::string hash = connection.key.PublicKeyHash(); log_verbose("Signature verification ok. Hash %s", hash.c_str()); } else { connection.authstatus = NETWORK_AUTH_VERIFICATIONFAILURE; log_verbose("Signature verification failed!"); } + if (gConfigNetwork.known_keys_only && key_group_map.find(hash) == key_group_map.end()) { + connection.authstatus = NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED; + } } const NetworkGroup * group = GetGroupByID(GetGroupIDByHash(connection.key.PublicKeyHash())); diff --git a/src/network/network.h b/src/network/network.h index b19c27553d..34ae8c0ee2 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -38,6 +38,7 @@ enum { NETWORK_AUTH_FULL, NETWORK_AUTH_REQUIREPASSWORD, NETWORK_AUTH_VERIFIED, + NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED, }; enum { diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c index 00be3e412d..e3ae28b6f7 100644 --- a/src/windows/top_toolbar.c +++ b/src/windows/top_toolbar.c @@ -109,7 +109,9 @@ typedef enum { } TOP_TOOLBAR_DEBUG_DDIDX; typedef enum { - DDIDX_MULTIPLAYER = 0 + DDIDX_MULTIPLAYER = 0, + // separator + DDIDX_KNOWN_KEYS_ONLY = 2 } TOP_TOOLBAR_NETWORK_DDIDX; enum { @@ -408,8 +410,8 @@ static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widg if (gConfigTwitch.channel != NULL && gConfigTwitch.channel[0] != 0) { _menuDropdownIncludesTwitch = true; gDropdownItemsFormat[12] = 0; - gDropdownItemsFormat[13] = 1156; - gDropdownItemsArgs[13] = STR_TWITCH_ENABLE; + gDropdownItemsFormat[DDIDX_ENABLE_TWITCH] = 1156; + gDropdownItemsArgs[DDIDX_ENABLE_TWITCH] = STR_TWITCH_ENABLE; numItems = 14; } #endif @@ -425,7 +427,7 @@ static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widg #ifndef DISABLE_TWITCH if (_menuDropdownIncludesTwitch && gTwitchEnable) { - dropdown_set_checked(13, true); + dropdown_set_checked(DDIDX_ENABLE_TWITCH, true); } #endif break; @@ -2955,6 +2957,15 @@ void top_toolbar_init_debug_menu(rct_window* w, rct_widget* widget) void top_toolbar_init_network_menu(rct_window* w, rct_widget* widget) { gDropdownItemsFormat[0] = STR_MULTIPLAYER; + int num_items = 1; + + if (network_get_mode() == NETWORK_MODE_SERVER) { + gDropdownItemsFormat[DDIDX_KNOWN_KEYS_ONLY - 1] = 0; + gDropdownItemsFormat[DDIDX_KNOWN_KEYS_ONLY] = 1156; + gDropdownItemsArgs[DDIDX_KNOWN_KEYS_ONLY] = STR_ALLOW_KNOWN_KEYS_ONLY; + // includes separator + num_items += 2; + } window_dropdown_show_text( w->x + widget->left, @@ -2962,9 +2973,13 @@ void top_toolbar_init_network_menu(rct_window* w, rct_widget* widget) widget->bottom - widget->top + 1, w->colours[0] | 0x80, 0, - 1 + num_items ); + if (network_get_mode() == NETWORK_MODE_SERVER && gConfigNetwork.known_keys_only) { + dropdown_set_checked(DDIDX_KNOWN_KEYS_ONLY, true); + } + gDropdownDefaultIndex = DDIDX_MULTIPLAYER; } @@ -3001,6 +3016,10 @@ void top_toolbar_network_menu_dropdown(short dropdownIndex) case DDIDX_MULTIPLAYER: window_multiplayer_open(); break; + case DDIDX_KNOWN_KEYS_ONLY: + gConfigNetwork.known_keys_only = !gConfigNetwork.known_keys_only; + config_save_default(); + break; } } }