Feature: authorize specific clients to join network company without password

This commit is contained in:
Rubidium 2024-03-23 13:38:37 +01:00 committed by rubidium42
parent 66354ab9eb
commit 4f3db8eeaf
8 changed files with 47 additions and 1 deletions

View File

@ -2487,6 +2487,7 @@ STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Your player nam
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Administrative actions to perform for this client
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Administrative actions to perform for this company
STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Join this company
STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP :{BLACK}Authorize this client to join your company
STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Send a message to this player
STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Send a message to all players of this company
STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Send a message to all spectators

View File

@ -126,6 +126,28 @@ NetworkClientInfo::~NetworkClientInfo()
return nullptr;
}
/**
* Returns whether the given company can be joined by this client.
* @param company_id The id of the company.
* @return \c true when this company is allowed to join, otherwise \c false.
*/
bool NetworkClientInfo::CanJoinCompany(CompanyID company_id) const
{
Company *c = Company::GetIfValid(company_id);
return c != nullptr && c->allow_list.Contains(this->public_key);
}
/**
* Returns whether the given company can be joined by this client.
* @param company_id The id of the company.
* @return \c true when this company is allowed to join, otherwise \c false.
*/
bool NetworkCanJoinCompany(CompanyID company_id)
{
NetworkClientInfo *info = NetworkClientInfo::GetByClientID(_network_own_client_id);
return info != nullptr && info->CanJoinCompany(company_id);
}
/**
* Return the client state given it's client-identifier
* @param client_id the ClientID to search for
@ -889,6 +911,9 @@ static void NetworkInitGameInfo()
ci->client_playas = COMPANY_SPECTATOR;
ci->client_name = _settings_client.network.client_name;
NetworkAuthenticationClientHandler::EnsureValidSecretKeyAndUpdatePublicKey(_settings_client.network.client_secret_key, _settings_client.network.client_public_key);
ci->public_key = _settings_client.network.client_public_key;
}
/**

View File

@ -36,6 +36,8 @@ struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_p
~NetworkClientInfo();
static NetworkClientInfo *GetByClientID(ClientID client_id);
bool CanJoinCompany(CompanyID company_id) const;
};
#endif /* NETWORK_BASE_H */

View File

@ -443,6 +443,15 @@ void CombinedAuthenticationServerHandler::Add(CombinedAuthenticationServerHandle
this->SendResponse();
}
/**
* Ensures that the given secret key is valid, and when not overwrite it with a valid secret key. Then update the public key to be associated with the secret key.
* @param secret_key The location where the secret key is stored; can be overwritten when invalid.
* @param public_key The location where the public key is stored; can be overwritten when invalid.
*/
/* static */ void NetworkAuthenticationClientHandler::EnsureValidSecretKeyAndUpdatePublicKey(std::string &secret_key, std::string &public_key)
{
X25519AuthorizedKeyClientHandler::GetValidSecretKeyAndUpdatePublicKey(secret_key, public_key);
}
/**
* Create a NetworkAuthenticationClientHandler.

View File

@ -248,6 +248,7 @@ public:
*/
virtual bool ReceiveEnableEncryption(struct Packet &p) = 0;
static void EnsureValidSecretKeyAndUpdatePublicKey(std::string &secret_key, std::string &public_key);
static std::unique_ptr<NetworkAuthenticationClientHandler> Create(std::shared_ptr<NetworkAuthenticationPasswordRequestHandler> password_handler, std::string &secret_key, std::string &public_key);
};

View File

@ -75,6 +75,7 @@ void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci);
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name);
bool NetworkCanJoinCompany(CompanyID company_id);
void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string);
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, ClientID from_id, int64_t data = 0, bool from_admin = false);

View File

@ -1536,6 +1536,12 @@ private:
ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, client_id);
}
static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id)
{
AutoRestoreBackup<CompanyID> cur_company(_current_company, NetworkClientInfo::GetByClientID(_network_own_client_id)->client_playas);
Command<CMD_COMPANY_ADD_ALLOW_LIST>::Post(NetworkClientInfo::GetByClientID(client_id)->public_key);
}
/**
* Part of RebuildList() to create the information for a single company.
* @param company_id The company to build the list for.
@ -1558,6 +1564,7 @@ private:
if (_network_server) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id));
if (_network_own_client_id != ci->client_id) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat));
if (_network_own_client_id != ci->client_id && client_playas != COMPANY_SPECTATOR && !ci->CanJoinCompany(client_playas)) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP, COLOUR_GREEN, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize));
if (ci->client_id == _network_own_client_id) {
this->player_self_index = this->line_count;

View File

@ -97,7 +97,7 @@ static CallBackFunction _last_started_action = CBF_NONE; ///< Last started user
*/
class DropDownListCompanyItem : public DropDownIcon<DropDownIcon<DropDownString<DropDownListItem>, true>> {
public:
DropDownListCompanyItem(CompanyID company, bool shaded) : DropDownIcon<DropDownIcon<DropDownString<DropDownListItem>, true>>(SPR_COMPANY_ICON, COMPANY_SPRITE_COLOUR(company), NetworkCompanyIsPassworded(company) ? SPR_LOCK : SPR_EMPTY, PAL_NONE, STR_NULL, company, false, shaded)
DropDownListCompanyItem(CompanyID company, bool shaded) : DropDownIcon<DropDownIcon<DropDownString<DropDownListItem>, true>>(SPR_COMPANY_ICON, COMPANY_SPRITE_COLOUR(company), NetworkCanJoinCompany(company) ? SPR_EMPTY : SPR_LOCK, PAL_NONE, STR_NULL, company, false, shaded)
{
SetDParam(0, company);
SetDParam(1, company);