don't check team names on serverside

http://gna.org/bugs/?23028

previously clients could add a "team_name" to specific packages which
should only be redirect to sides in this team. But the serversided code
which calculated in which team a side was had some bugs:
1) It did not correctly handle sides that were in multiple teams
([side] team_name="team1,team2"...)
2) The serversided data about teams was not updated when wml changed the
teams, also the calculation which side was controlled by a human used
posssibly oudated information.

This commit moves this calculation to the sending client so that the
clients now must specify a list of sides to which the package should be
sended.
This commit is contained in:
gfgtdf 2015-06-09 19:45:07 +02:00
parent 15698bbea6
commit 6aa3b3bc9a
7 changed files with 93 additions and 53 deletions

View file

@ -2550,9 +2550,9 @@ void menu_handler::send_chat_message(const std::string& message, bool allies_onl
if(private_message) { if(private_message) {
if (board().is_observer()) { if (board().is_observer()) {
cfg["team_name"] = game_config::observer_team_name; cfg["to_sides"] = game_config::observer_team_name;
} else { } else {
cfg["team_name"] = teams()[gui_->viewing_team()].team_name(); cfg["to_sides"] = teams()[gui_->viewing_team()].allied_human_teams();
} }
} }

View file

@ -25,6 +25,7 @@
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <boost/foreach.hpp>
static lg::log_domain log_server("server"); static lg::log_domain log_server("server");
#define ERR_GAME LOG_STREAM(err, log_server) #define ERR_GAME LOG_STREAM(err, log_server)
@ -34,6 +35,38 @@ static lg::log_domain log_server("server");
static lg::log_domain log_config("config"); static lg::log_domain log_config("config");
#define WRN_CONFIG LOG_STREAM(warn, log_config) #define WRN_CONFIG LOG_STREAM(warn, log_config)
namespace
{
struct split_conv_impl
{
void operator()(std::vector<int> res, const simple_wml::string_span& span)
{
if(!span.empty()) {
res.push_back(span.to_int());
}
}
};
template<typename TResult, typename TConvert>
std::vector<TResult> split(const simple_wml::string_span& val, TConvert conv, const char c = ',')
{
std::vector<TResult> res;
simple_wml::string_span::const_iterator i1 = val.begin();
simple_wml::string_span::const_iterator i2 = i1;
while (i2 != val.end()) {
if (*i2 == c) {
conv(res, simple_wml::string_span(i1, i2));
++i2;
i1 = i2;
} else {
++i2;
}
}
conv(res, simple_wml::string_span(i1, i2));
return res;
}
}
namespace wesnothd { namespace wesnothd {
int game::id_num = 1; int game::id_num = 1;
@ -898,7 +931,7 @@ bool game::process_turn(simple_wml::document& data, const player_map::const_iter
marked.push_back(index - marked.size()); marked.push_back(index - marked.size());
} else if ((**command).child("speak")) { } else if ((**command).child("speak")) {
simple_wml::node& speak = *(**command).child("speak"); simple_wml::node& speak = *(**command).child("speak");
if (speak["team_name"] != "" || is_muted_observer(user->first)) { if (speak["to_sides"] != "" || is_muted_observer(user->first)) {
DBG_GAME << "repackaging..." << std::endl; DBG_GAME << "repackaging..." << std::endl;
repackage = true; repackage = true;
} }
@ -950,35 +983,25 @@ bool game::process_turn(simple_wml::document& data, const player_map::const_iter
record_data(mdata); record_data(mdata);
continue; continue;
} }
const simple_wml::string_span& team_name = (*speak)["team_name"]; const simple_wml::string_span& to_sides = (*speak)["to_sides"];
// Anyone can send to the observer team. // Anyone can send to the observer team.
if (team_name == game_config::observer_team_name.c_str()) { if (is_muted_observer(user->first) && to_sides != game_config::observer_team_name.c_str()) {
// Don't send if the member is muted.
} else if (is_muted_observer(user->first)) {
send_server_message("You have been muted, others can't see your message!", user->first); send_server_message("You have been muted, others can't see your message!", user->first);
continue; continue;
// Don't send if the player addresses a different team.
} else if (!is_on_team(team_name, user->first)) {
std::ostringstream msg;
msg << "Removing illegal message from " << user->second.name() << " to " << std::string(team_name.begin(), team_name.end()) << ".";
const std::string& msg_str = msg.str();
LOG_GAME << msg_str << std::endl;
send_and_record_server_message(msg_str);
continue;
} }
std::auto_ptr<simple_wml::document> message(new simple_wml::document); std::auto_ptr<simple_wml::document> message(new simple_wml::document);
simple_wml::node& turn = message->root().add_child("turn"); simple_wml::node& turn = message->root().add_child("turn");
simple_wml::node& command = turn.add_child("command"); simple_wml::node& command = turn.add_child("command");
speak->copy_into(command.add_child("speak")); speak->copy_into(command.add_child("speak"));
if (team_name == "") { if (to_sides == "") {
send_data(*message, user->first, "game message"); send_data(*message, user->first, "game message");
record_data(message.release()); record_data(message.release());
} else if (team_name == game_config::observer_team_name) { } else if (to_sides == game_config::observer_team_name) {
wesnothd::send_to_many(*message, observers_, user->first, "game message"); wesnothd::send_to_many(*message, observers_, user->first, "game message");
record_data(message.release()); record_data(message.release());
} else { } else {
send_data_team(*message, team_name, user->first, "game message"); send_data_sides(*message, to_sides, user->first, "game message");
} }
} }
return turn_ended; return turn_ended;
@ -1041,23 +1064,22 @@ void game::process_whiteboard(simple_wml::document& data, const player_map::cons
simple_wml::node const& wb_node = *data.child("whiteboard"); simple_wml::node const& wb_node = *data.child("whiteboard");
// Ensure "side" and "team_name" attributes match with user // Ensure "side" attribute match with user
simple_wml::string_span const& team_name = wb_node["team_name"]; simple_wml::string_span const& to_sides = wb_node["to_sides"];
size_t const side_index = wb_node["side"].to_int() - 1; size_t const side_index = wb_node["side"].to_int() - 1;
if(!is_on_team(team_name, user->first) if(side_index >= sides_.size()
|| side_index >= sides_.size()
|| sides_[side_index] != user->first) || sides_[side_index] != user->first)
{ {
std::ostringstream msg; std::ostringstream msg;
msg << "Ignoring illegal whiteboard data, sent from user '" << user->second.name() msg << "Ignoring illegal whiteboard data, sent from user '" << user->second.name()
<< "' to team '" << std::string(team_name.begin(), team_name.end()) << "'." << std::endl; << "' which had an invalid side '" << side_index + 1 << "' specified" << std::endl;
const std::string& msg_str = msg.str(); const std::string& msg_str = msg.str();
LOG_GAME << msg_str << std::endl; LOG_GAME << msg_str << std::endl;
send_and_record_server_message(msg_str); send_and_record_server_message(msg_str);
return; return;
} }
send_data_team(data,team_name,user->first,"whiteboard"); send_data_sides(data, to_sides, user->first, "whiteboard");
} }
void game::process_change_controller_wml(simple_wml::document& data, const player_map::const_iterator user) void game::process_change_controller_wml(simple_wml::document& data, const player_map::const_iterator user)
@ -1105,7 +1127,7 @@ bool game::end_turn() {
if (description_ == NULL) { if (description_ == NULL) {
return false; return false;
} }
//FIXME: this "turn" attribute migth be outdated if teh number of turns was changed by wml.
description_->set_attr_dup("turn", describe_turns(current_turn(), level_["turns"]).c_str()); description_->set_attr_dup("turn", describe_turns(current_turn(), level_["turns"]).c_str());
return true; return true;
@ -1355,49 +1377,42 @@ void game::send_data(simple_wml::document& data,
wesnothd::send_to_many(data, all_game_users(), exclude, packet_type); wesnothd::send_to_many(data, all_game_users(), exclude, packet_type);
} }
namespace { namespace {
struct is_on_team_helper struct controls_side_helper
{ {
const wesnothd::game& game_; const wesnothd::game& game_;
const simple_wml::string_span& team_; const std::vector<int>& sides_;
is_on_team_helper(const wesnothd::game& game, const simple_wml::string_span& team) controls_side_helper(const wesnothd::game& game, const std::vector<int>& sides)
: game_(game) : game_(game)
, team_(team) , sides_(sides)
{ {
} }
bool operator ()(network::connection user) const bool operator ()(network::connection user) const
{ {
return game_.is_on_team(team_, user); return game_.controls_side(sides_, user);
} }
}; };
} }
void game::send_data_team(simple_wml::document& data,
const simple_wml::string_span& team, void game::send_data_sides(simple_wml::document& data,
const simple_wml::string_span& sides,
const network::connection exclude, const network::connection exclude,
std::string packet_type) const std::string packet_type) const
{ {
std::vector<int> sides_vec = ::split<int>(sides, ::split_conv_impl());
DBG_GAME << __func__ << "...\n"; DBG_GAME << __func__ << "...\n";
wesnothd::send_to_many(data, players_, is_on_team_helper(*this, team), exclude, packet_type); wesnothd::send_to_many(data, players_, controls_side_helper(*this, sides_vec), exclude, packet_type);
} }
bool game::controls_side(const std::vector<int>& sides, const network::connection player) const
bool game::is_on_team(const simple_wml::string_span& team, const network::connection player) const { {
const simple_wml::node::child_list& side_list = get_sides_list(); BOOST_FOREACH(int side, sides)
for (side_vector::const_iterator side = sides_.begin(); side != sides_.end(); ++side) { {
if (*side != player) continue; size_t side_index = side - 1;
for (simple_wml::node::child_list::const_iterator i = side_list.begin(); if(side_index < sides_.size() && sides_[side_index] == player) {
i != side_list.end(); ++i) {
if ((**i)["side"].to_int() != side - sides_.begin() + 1) continue;
if ((**i)["team_name"] != team) continue;
// Don't consider ai sides on a team.
if ((**i)["controller"] == "ai") continue;
if (side_controllers_[side - sides_.begin()] == "ai") continue;
DBG_GAME << "side: " << (**i)["side"].to_int() << " with team_name: " << (**i)["team_name"]
<< " belongs to player: " << player << std::endl;
return true; return true;
} }
} }
return false; return false;
} }

View file

@ -227,10 +227,9 @@ public:
void reset_last_synced_context_id() { last_synced_context_id_ = -1; } void reset_last_synced_context_id() { last_synced_context_id_ = -1; }
/** /**
* Function which returns true iff 'player' is on 'team'. * Function which returns true iff 'player' controls any of the sides spcified in 'sides'.
* AI controlled sides are not considered on a team.
*/ */
bool is_on_team(const simple_wml::string_span& team, const network::connection player) const; bool controls_side(const std::vector<int>& sides, const network::connection player) const;
private: private:
//forbidden operations //forbidden operations
game(const game&); game(const game&);
@ -268,7 +267,10 @@ private:
const std::string& controller = ""); const std::string& controller = "");
void transfer_ai_sides(const network::connection player); void transfer_ai_sides(const network::connection player);
void send_leave_game(network::connection user) const; void send_leave_game(network::connection user) const;
void send_data_team(simple_wml::document& data, const simple_wml::string_span& team, /**
@param sides: a comma sperated list of side numbers to which the package should be sent,
*/
void send_data_sides(simple_wml::document& data, const simple_wml::string_span& sides,
const network::connection exclude=0, std::string packet_type = "") const; const network::connection exclude=0, std::string packet_type = "") const;
void send_data_observers(simple_wml::document& data, const network::connection exclude=0, std::string packet_type = "") const; void send_data_observers(simple_wml::document& data, const network::connection exclude=0, std::string packet_type = "") const;

View file

@ -40,6 +40,12 @@ public:
{} {}
string_span(const char* str) : str_(str), size_(strlen(str)) string_span(const char* str) : str_(str), size_(strlen(str))
{} {}
string_span(const char* begin, const char* end) : str_(begin), size_(end - begin)
{}
typedef const char* const_iterator;
typedef const char* iterator;
typedef const char value_type;
bool operator==(const char* o) const { bool operator==(const char* o) const {
const char* i1 = str_; const char* i1 = str_;

View file

@ -33,6 +33,7 @@
#include "whiteboard/side_actions.hpp" #include "whiteboard/side_actions.hpp"
#include "network.hpp" #include "network.hpp"
#include "config_assign.hpp" #include "config_assign.hpp"
#include "serialization/string_utils.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
@ -851,3 +852,15 @@ config team::to_config() const
write(result); write(result);
return result; return result;
} }
std::string team::allied_human_teams() const
{
std::vector<int> res;
BOOST_FOREACH(const team& t, *teams)
{
if(!t.is_enemy(this->side()) && t.is_human()) {
res.push_back(t.side());
}
}
return utils::join(res);
}

View file

@ -258,6 +258,8 @@ public:
bool is_local() const { return is_local_human() || is_local_ai(); } bool is_local() const { return is_local_human() || is_local_ai(); }
bool is_network() const { return is_network_human() || is_network_ai(); } bool is_network() const { return is_network_human() || is_network_ai(); }
bool is_human() const { return is_local_human() || is_network_human(); }
bool is_local_human() const { return info_.controller == CONTROLLER::HUMAN; } bool is_local_human() const { return info_.controller == CONTROLLER::HUMAN; }
bool is_local_ai() const { return info_.controller == CONTROLLER::AI; } bool is_local_ai() const { return info_.controller == CONTROLLER::AI; }
bool is_network_human() const { return info_.controller == CONTROLLER::NETWORK; } bool is_network_human() const { return info_.controller == CONTROLLER::NETWORK; }
@ -376,6 +378,8 @@ public:
bool share_maps() const { return info_.share_maps; } bool share_maps() const { return info_.share_maps; }
bool share_view() const { return info_.share_view; } bool share_view() const { return info_.share_view; }
std::string allied_human_teams() const;
private: private:
const std::vector<const shroud_map*>& ally_shroud(const std::vector<team>& teams) const; const std::vector<const shroud_map*>& ally_shroud(const std::vector<team>& teams) const;

View file

@ -609,7 +609,7 @@ void manager::send_network_data()
config packet; config packet;
config& wb_cfg = packet.add_child("whiteboard",buf_cfg); config& wb_cfg = packet.add_child("whiteboard",buf_cfg);
wb_cfg["side"] = static_cast<int>(team_index+1); wb_cfg["side"] = static_cast<int>(team_index+1);
wb_cfg["team_name"] = resources::teams->at(team_index).team_name(); wb_cfg["to_sides"] = resources::teams->at(team_index).allied_human_teams();
buf_cfg = config(); buf_cfg = config();