mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-09 07:29:44 +00:00
Codechange: introduce allow list infrastructure for companies
This commit is contained in:
parent
1250ce8fdc
commit
66354ab9eb
@ -294,6 +294,7 @@ enum Commands : uint16_t {
|
|||||||
|
|
||||||
CMD_CREATE_SUBSIDY, ///< create a new subsidy
|
CMD_CREATE_SUBSIDY, ///< create a new subsidy
|
||||||
CMD_COMPANY_CTRL, ///< used in multiplayer to create a new companies etc.
|
CMD_COMPANY_CTRL, ///< used in multiplayer to create a new companies etc.
|
||||||
|
CMD_COMPANY_ADD_ALLOW_LIST, ///< Used in multiplayer to add a client's public key to the company's allow list.
|
||||||
CMD_CUSTOM_NEWS_ITEM, ///< create a custom news message
|
CMD_CUSTOM_NEWS_ITEM, ///< create a custom news message
|
||||||
CMD_CREATE_GOAL, ///< create a new goal
|
CMD_CREATE_GOAL, ///< create a new goal
|
||||||
CMD_REMOVE_GOAL, ///< remove a goal
|
CMD_REMOVE_GOAL, ///< remove a goal
|
||||||
|
@ -75,6 +75,8 @@ struct CompanyProperties {
|
|||||||
uint32_t president_name_2; ///< Parameter of #president_name_1
|
uint32_t president_name_2; ///< Parameter of #president_name_1
|
||||||
std::string president_name; ///< Name of the president if the user changed it.
|
std::string president_name; ///< Name of the president if the user changed it.
|
||||||
|
|
||||||
|
NetworkAuthorizedKeys allow_list; ///< Public keys of clients that are allowed to join this company.
|
||||||
|
|
||||||
CompanyManagerFace face; ///< Face description of the president.
|
CompanyManagerFace face; ///< Face description of the president.
|
||||||
|
|
||||||
Money money; ///< Money owned by the company.
|
Money money; ///< Money owned by the company.
|
||||||
|
@ -980,6 +980,24 @@ CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID
|
|||||||
return CommandCost();
|
return CommandCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given public key to the allow list of this company.
|
||||||
|
* @param flags Operation to perform.
|
||||||
|
* @param public_key The public key of the client to add.
|
||||||
|
* @return The cost of this operation or an error.
|
||||||
|
*/
|
||||||
|
CommandCost CmdCompanyAddAllowList(DoCommandFlag flags, const std::string &public_key)
|
||||||
|
{
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
if (Company::Get(_current_company)->allow_list.Add(public_key)) {
|
||||||
|
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||||
|
SetWindowDirty(WC_COMPANY, _current_company);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommandCost();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the company manager's face.
|
* Change the company manager's face.
|
||||||
* @param flags operation to perform
|
* @param flags operation to perform
|
||||||
|
@ -18,6 +18,7 @@ enum ClientID : uint32_t;
|
|||||||
enum Colours : uint8_t;
|
enum Colours : uint8_t;
|
||||||
|
|
||||||
CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
|
CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
|
||||||
|
CommandCost CmdCompanyAddAllowList(DoCommandFlag flags, const std::string &public_key);
|
||||||
CommandCost CmdGiveMoney(DoCommandFlag flags, Money money, CompanyID dest_company);
|
CommandCost CmdGiveMoney(DoCommandFlag flags, Money money, CompanyID dest_company);
|
||||||
CommandCost CmdRenameCompany(DoCommandFlag flags, const std::string &text);
|
CommandCost CmdRenameCompany(DoCommandFlag flags, const std::string &text);
|
||||||
CommandCost CmdRenamePresident(DoCommandFlag flags, const std::string &text);
|
CommandCost CmdRenamePresident(DoCommandFlag flags, const std::string &text);
|
||||||
@ -25,6 +26,7 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlag flags, CompanyManagerFace cmf
|
|||||||
CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool primary, Colours colour);
|
CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool primary, Colours colour);
|
||||||
|
|
||||||
DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID | CMD_NO_EST, CMDT_SERVER_SETTING)
|
DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID | CMD_NO_EST, CMDT_SERVER_SETTING)
|
||||||
|
DEF_CMD_TRAIT(CMD_COMPANY_ADD_ALLOW_LIST, CmdCompanyAddAllowList, CMD_NO_EST, CMDT_SERVER_SETTING)
|
||||||
DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, 0, CMDT_MONEY_MANAGEMENT)
|
DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, 0, CMDT_MONEY_MANAGEMENT)
|
||||||
DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, 0, CMDT_OTHER_MANAGEMENT)
|
DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, 0, CMDT_OTHER_MANAGEMENT)
|
||||||
DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, 0, CMDT_OTHER_MANAGEMENT)
|
DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, 0, CMDT_OTHER_MANAGEMENT)
|
||||||
|
@ -96,5 +96,10 @@ static const uint NETWORK_MAX_GRF_COUNT = 255;
|
|||||||
* This is related to \c X25519_KEY_SIZE in the network crypto internals.
|
* This is related to \c X25519_KEY_SIZE in the network crypto internals.
|
||||||
*/
|
*/
|
||||||
static const uint NETWORK_SECRET_KEY_LENGTH = 32 * 2 + 1;
|
static const uint NETWORK_SECRET_KEY_LENGTH = 32 * 2 + 1;
|
||||||
|
/**
|
||||||
|
* The maximum length of the hexadecimal encoded public keys, in bytes including '\0'.
|
||||||
|
* This is related to \c X25519_KEY_SIZE in the network crypto internals.
|
||||||
|
*/
|
||||||
|
static const uint NETWORK_PUBLIC_KEY_LENGTH = 32 * 2 + 1;
|
||||||
|
|
||||||
#endif /* NETWORK_CORE_CONFIG_H */
|
#endif /* NETWORK_CORE_CONFIG_H */
|
||||||
|
@ -202,7 +202,8 @@ protected:
|
|||||||
* Send information about a client:
|
* Send information about a client:
|
||||||
* uint32_t ID of the client (always unique on a server. 1 = server, 0 is invalid).
|
* uint32_t ID of the client (always unique on a server. 1 = server, 0 is invalid).
|
||||||
* uint8_t ID of the company the client is playing as (255 for spectators).
|
* uint8_t ID of the company the client is playing as (255 for spectators).
|
||||||
* string Name of the client.
|
* string Name of the client.
|
||||||
|
* string Public key of the client.
|
||||||
* @param p The packet that was just received.
|
* @param p The packet that was just received.
|
||||||
*/
|
*/
|
||||||
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p);
|
virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p);
|
||||||
|
@ -165,10 +165,12 @@ bool NetworkAuthorizedKeys::Contains(std::string_view key) const
|
|||||||
/**
|
/**
|
||||||
* Add the given key to the authorized keys, when it is not already contained.
|
* Add the given key to the authorized keys, when it is not already contained.
|
||||||
* @param key The key to add.
|
* @param key The key to add.
|
||||||
* @return \c true when the key was added, \c false when the key already existed.
|
* @return \c true when the key was added, \c false when the key already existed or the key was empty.
|
||||||
*/
|
*/
|
||||||
bool NetworkAuthorizedKeys::Add(std::string_view key)
|
bool NetworkAuthorizedKeys::Add(std::string_view key)
|
||||||
{
|
{
|
||||||
|
if (key.empty()) return false;
|
||||||
|
|
||||||
auto iter = FindKey(this, key);
|
auto iter = FindKey(this, key);
|
||||||
if (iter != this->end()) return false;
|
if (iter != this->end()) return false;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ extern NetworkClientInfoPool _networkclientinfo_pool;
|
|||||||
struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_pool> {
|
struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_pool> {
|
||||||
ClientID client_id; ///< Client identifier (same as ClientState->client_id)
|
ClientID client_id; ///< Client identifier (same as ClientState->client_id)
|
||||||
std::string client_name; ///< Name of the client
|
std::string client_name; ///< Name of the client
|
||||||
|
std::string public_key; ///< The public key of the client.
|
||||||
CompanyID client_playas; ///< As which company is this client playing (CompanyID)
|
CompanyID client_playas; ///< As which company is this client playing (CompanyID)
|
||||||
TimerGameEconomy::Date join_date; ///< Gamedate the client has joined
|
TimerGameEconomy::Date join_date; ///< Gamedate the client has joined
|
||||||
|
|
||||||
|
@ -608,6 +608,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
|||||||
Debug(net, 9, "Client::Receive_SERVER_CLIENT_INFO(): client_id={}, playas={}", client_id, playas);
|
Debug(net, 9, "Client::Receive_SERVER_CLIENT_INFO(): client_id={}, playas={}", client_id, playas);
|
||||||
|
|
||||||
std::string name = p.Recv_string(NETWORK_NAME_LENGTH);
|
std::string name = p.Recv_string(NETWORK_NAME_LENGTH);
|
||||||
|
std::string public_key = p.Recv_string(NETWORK_PUBLIC_KEY_LENGTH);
|
||||||
|
|
||||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
|
||||||
@ -632,6 +633,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
|||||||
|
|
||||||
ci->client_playas = playas;
|
ci->client_playas = playas;
|
||||||
ci->client_name = name;
|
ci->client_name = name;
|
||||||
|
ci->public_key = public_key;
|
||||||
|
|
||||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||||
|
|
||||||
@ -651,6 +653,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
|||||||
if (client_id == _network_own_client_id) this->SetInfo(ci);
|
if (client_id == _network_own_client_id) this->SetInfo(ci);
|
||||||
|
|
||||||
ci->client_name = name;
|
ci->client_name = name;
|
||||||
|
ci->public_key = public_key;
|
||||||
|
|
||||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||||
|
|
||||||
|
@ -332,6 +332,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn
|
|||||||
p->Send_uint32(ci->client_id);
|
p->Send_uint32(ci->client_id);
|
||||||
p->Send_uint8 (ci->client_playas);
|
p->Send_uint8 (ci->client_playas);
|
||||||
p->Send_string(ci->client_name);
|
p->Send_string(ci->client_name);
|
||||||
|
p->Send_string(ci->public_key);
|
||||||
|
|
||||||
this->SendPacket(std::move(p));
|
this->SendPacket(std::move(p));
|
||||||
}
|
}
|
||||||
@ -959,6 +960,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet
|
|||||||
ci->join_date = TimerGameEconomy::date;
|
ci->join_date = TimerGameEconomy::date;
|
||||||
ci->client_name = client_name;
|
ci->client_name = client_name;
|
||||||
ci->client_playas = playas;
|
ci->client_playas = playas;
|
||||||
|
ci->public_key = this->peer_public_key;
|
||||||
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, (int)ci->client_playas, (int)ci->index);
|
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, (int)ci->client_playas, (int)ci->index);
|
||||||
|
|
||||||
/* Make sure companies to which people try to join are not autocleaned */
|
/* Make sure companies to which people try to join are not autocleaned */
|
||||||
@ -1177,6 +1179,23 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cp.cmd == CMD_COMPANY_ADD_ALLOW_LIST) {
|
||||||
|
/* Maybe the client just got moved before allowing? */
|
||||||
|
if (ci->client_id != CLIENT_ID_SERVER && ci->client_playas != cp.company) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
|
std::string public_key = std::get<0>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_ADD_ALLOW_LIST>::Args>(cp.data));
|
||||||
|
bool found = false;
|
||||||
|
for (const NetworkClientInfo *info : NetworkClientInfo::Iterate()) {
|
||||||
|
if (info->public_key == public_key) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Maybe the client just left? */
|
||||||
|
if (!found) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) NetworkReplaceCommandClientId(cp, this->client_id);
|
if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) NetworkReplaceCommandClientId(cp, this->client_id);
|
||||||
|
|
||||||
this->incoming_queue.push_back(cp);
|
this->incoming_queue.push_back(cp);
|
||||||
@ -1541,7 +1560,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &p)
|
|||||||
if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
|
if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
/* Check if we require a password for this company */
|
/* Check if we require a password for this company */
|
||||||
if (company_id != COMPANY_SPECTATOR && !_network_company_states[company_id].password.empty()) {
|
if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key) && !_network_company_states[company_id].password.empty()) {
|
||||||
/* we need a password from the client - should be in this packet */
|
/* we need a password from the client - should be in this packet */
|
||||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||||
|
|
||||||
@ -2275,13 +2294,9 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
|
|||||||
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
|
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
|
||||||
ci->client_playas = c->index;
|
ci->client_playas = c->index;
|
||||||
NetworkUpdateClientInfo(ci->client_id);
|
NetworkUpdateClientInfo(ci->client_id);
|
||||||
|
Command<CMD_COMPANY_ADD_ALLOW_LIST>::SendNet(STR_NULL, c->index, ci->public_key);
|
||||||
Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, c->index, ci->client_name);
|
Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, c->index, ci->client_name);
|
||||||
}
|
|
||||||
|
|
||||||
if (ci != nullptr) {
|
|
||||||
/* ci is nullptr when replaying, or for AIs. In neither case there is a client.
|
|
||||||
We need to send Admin port update here so that they first know about the new company
|
|
||||||
and then learn about a possibly joining client (see FS#6025) */
|
|
||||||
NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
|
NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,6 +450,8 @@ static const SaveLoad _company_desc[] = {
|
|||||||
SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32),
|
SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32),
|
||||||
SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION),
|
SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION),
|
||||||
|
|
||||||
|
SLE_CONDVECTOR(CompanyProperties, allow_list, SLE_STR, SLV_COMPANY_ALLOW_LIST, SL_MAX_VERSION),
|
||||||
|
|
||||||
SLE_VAR(CompanyProperties, face, SLE_UINT32),
|
SLE_VAR(CompanyProperties, face, SLE_UINT32),
|
||||||
|
|
||||||
/* money was changed to a 64 bit field in savegame version 1. */
|
/* money was changed to a 64 bit field in savegame version 1. */
|
||||||
|
@ -379,6 +379,8 @@ enum SaveLoadVersion : uint16_t {
|
|||||||
SLV_SCRIPT_RANDOMIZER, ///< 333 PR#12063 v14.0-RC1 Save script randomizers.
|
SLV_SCRIPT_RANDOMIZER, ///< 333 PR#12063 v14.0-RC1 Save script randomizers.
|
||||||
SLV_VEHICLE_ECONOMY_AGE, ///< 334 PR#12141 v14.0 Add vehicle age in economy year, for profit stats minimum age
|
SLV_VEHICLE_ECONOMY_AGE, ///< 334 PR#12141 v14.0 Add vehicle age in economy year, for profit stats minimum age
|
||||||
|
|
||||||
|
SLV_COMPANY_ALLOW_LIST, ///< 335 PR#12337 Saving of list of client keys that are allowed to join this company.
|
||||||
|
|
||||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
/* The length of the hexadecimal representation of a X25519 key must fit in the key length. */
|
/* The length of the hexadecimal representation of a X25519 key must fit in the key length. */
|
||||||
static_assert(NETWORK_SECRET_KEY_LENGTH >= X25519_KEY_SIZE * 2 + 1);
|
static_assert(NETWORK_SECRET_KEY_LENGTH >= X25519_KEY_SIZE * 2 + 1);
|
||||||
|
static_assert(NETWORK_PUBLIC_KEY_LENGTH >= X25519_KEY_SIZE * 2 + 1);
|
||||||
|
|
||||||
class MockNetworkSocketHandler : public NetworkSocketHandler {
|
class MockNetworkSocketHandler : public NetworkSocketHandler {
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user