escape player-provided text in various places

This commit is contained in:
Martin Michelsen
2023-12-26 07:37:00 -08:00
parent 5382e12b8d
commit ccd1b56cae
6 changed files with 74 additions and 25 deletions
+13 -11
View File
@@ -639,7 +639,7 @@ static void proxy_command_get_player_card(shared_ptr<ProxyServer::LinkedSession>
send_guild_card(ses->client_channel, p.guild_card_number, p.guild_card_number, p.name, "", "", p.language, p.section_id, p.char_class); send_guild_card(ses->client_channel, p.guild_card_number, p.guild_card_number, p.name, "", "", p.language, p.section_id, p.char_class);
} }
} catch (const exception& e) { } catch (const exception& e) {
send_text_message_printf(ses->client_channel, "Error: %s", e.what()); send_text_message(ses->client_channel, "Error: " + remove_color(e.what()));
} }
} }
} }
@@ -685,7 +685,7 @@ static void server_command_lobby_event(shared_ptr<Client> c, const std::string&
uint8_t new_event = event_for_name(args); uint8_t new_event = event_for_name(args);
if (new_event == 0xFF) { if (new_event == 0xFF) {
send_text_message(c, "$C6No such lobby event."); send_text_message(c, "$C6No such lobby event");
return; return;
} }
@@ -699,7 +699,7 @@ static void proxy_command_lobby_event(shared_ptr<ProxyServer::LinkedSession> ses
} else { } else {
uint8_t new_event = event_for_name(args); uint8_t new_event = event_for_name(args);
if (new_event == 0xFF) { if (new_event == 0xFF) {
send_text_message(ses->client_channel, "$C6No such lobby event."); send_text_message(ses->client_channel, "$C6No such lobby event");
} else { } else {
ses->config.override_lobby_event = new_event; ses->config.override_lobby_event = new_event;
if (!is_v1_or_v2(ses->version())) { if (!is_v1_or_v2(ses->version())) {
@@ -714,7 +714,7 @@ static void server_command_lobby_event_all(shared_ptr<Client> c, const std::stri
uint8_t new_event = event_for_name(args); uint8_t new_event = event_for_name(args);
if (new_event == 0xFF) { if (new_event == 0xFF) {
send_text_message(c, "$C6No such lobby event."); send_text_message(c, "$C6No such lobby event");
return; return;
} }
@@ -919,7 +919,8 @@ static void server_command_password(shared_ptr<Client> c, const std::string& arg
} else { } else {
l->password = args; l->password = args;
send_text_message_printf(l, "$C6Game password:\n%s", l->password.c_str()); string escaped = remove_color(l->password);
send_text_message_printf(l, "$C6Game password:\n%s", escaped.c_str());
} }
} }
@@ -1113,7 +1114,8 @@ static void server_command_change_bank(shared_ptr<Client> c, const std::string&
} else if (new_char_index <= 4) { } else if (new_char_index <= 4) {
c->use_character_bank(new_char_index - 1); c->use_character_bank(new_char_index - 1);
auto bp = c->current_bank_character(); auto bp = c->current_bank_character();
auto name = bp->disp.name.decode(c->language());
auto name = escape_player_name(bp->disp.name.decode(c->language()));
send_text_message_printf(c, "$C6Using %s\'s bank (%zu)", name.c_str(), new_char_index); send_text_message_printf(c, "$C6Using %s\'s bank (%zu)", name.c_str(), new_char_index);
} else { } else {
throw runtime_error("invalid bank number"); throw runtime_error("invalid bank number");
@@ -1201,7 +1203,7 @@ static void server_command_save(shared_ptr<Client> c, const std::string&) {
c->save_all(); c->save_all();
send_text_message(c, "All data saved"); send_text_message(c, "All data saved");
} catch (const exception& e) { } catch (const exception& e) {
send_text_message_printf(c, "Can\'t save data:\n%s", e.what()); send_text_message(c, "Can\'t save data:\n" + remove_color(e.what()));
} }
c->reschedule_save_game_data_event(); c->reschedule_save_game_data_event();
} }
@@ -1212,7 +1214,7 @@ static void server_command_save(shared_ptr<Client> c, const std::string&) {
static string name_for_client(shared_ptr<Client> c) { static string name_for_client(shared_ptr<Client> c) {
auto player = c->character(false); auto player = c->character(false);
if (player.get()) { if (player.get()) {
return player->disp.name.decode(player->inventory.language); return escape_player_name(player->disp.name.decode(player->inventory.language));
} }
if (c->license.get()) { if (c->license.get()) {
@@ -1778,7 +1780,7 @@ static void server_command_surrender(shared_ptr<Client> c, const std::string&) {
send_text_message(c, "$C6Battle has not\nyet started"); send_text_message(c, "$C6Battle has not\nyet started");
return; return;
} }
const string& name = c->character()->disp.name.decode(c->language()); string name = remove_color(c->character()->disp.name.decode(c->language()));
send_text_message_printf(l, "$C6%s has\nsurrendered", name.c_str()); send_text_message_printf(l, "$C6%s has\nsurrendered", name.c_str());
for (const auto& watcher_l : l->watcher_lobbies) { for (const auto& watcher_l : l->watcher_lobbies) {
send_text_message_printf(watcher_l, "$C6%s has\nsurrendered", name.c_str()); send_text_message_printf(watcher_l, "$C6%s has\nsurrendered", name.c_str());
@@ -1983,7 +1985,7 @@ void on_chat_command(std::shared_ptr<Client> c, const std::string& text) {
} catch (const precondition_failed& e) { } catch (const precondition_failed& e) {
send_text_message(c, e.what()); send_text_message(c, e.what());
} catch (const exception& e) { } catch (const exception& e) {
send_text_message_printf(c, "$C6Failed:\n%s", e.what()); send_text_message(c, "$C6Failed:\n" + remove_color(e.what()));
} }
} }
} }
@@ -2007,7 +2009,7 @@ void on_chat_command(shared_ptr<ProxyServer::LinkedSession> ses, const std::stri
} catch (const precondition_failed& e) { } catch (const precondition_failed& e) {
send_text_message(ses->client_channel, e.what()); send_text_message(ses->client_channel, e.what());
} catch (const exception& e) { } catch (const exception& e) {
send_text_message_printf(ses->client_channel, "$C6Failed:\n%s", e.what()); send_text_message(ses->client_channel, "$C6Failed:\n" + remove_color(e.what()));
} }
} }
} }
+3 -3
View File
@@ -1400,8 +1400,7 @@ static HandlerResult S_65_67_68_EB(shared_ptr<ProxyServer::LinkedSession> ses, u
if (index >= ses->lobby_players.size()) { if (index >= ses->lobby_players.size()) {
ses->log.warning("Ignoring invalid player index %zu at position %zu", index, x); ses->log.warning("Ignoring invalid player index %zu at position %zu", index, x);
} else { } else {
string name = entry.disp.visual.name.decode(entry.inventory.language); string name = escape_player_name(entry.disp.visual.name.decode(entry.inventory.language));
if (ses->license && (entry.lobby_data.guild_card_number == ses->remote_guild_card_number)) { if (ses->license && (entry.lobby_data.guild_card_number == ses->remote_guild_card_number)) {
entry.lobby_data.guild_card_number = ses->license->serial_number; entry.lobby_data.guild_card_number = ses->license->serial_number;
num_replacements++; num_replacements++;
@@ -1578,9 +1577,10 @@ static HandlerResult S_66_69_E9(shared_ptr<ProxyServer::LinkedSession> ses, uint
ses->log.warning("Lobby leave command references missing position"); ses->log.warning("Lobby leave command references missing position");
} else { } else {
auto& p = ses->lobby_players[index]; auto& p = ses->lobby_players[index];
string name = escape_player_name(p.name);
if (ses->config.check_flag(Client::Flag::PROXY_PLAYER_NOTIFICATIONS_ENABLED)) { if (ses->config.check_flag(Client::Flag::PROXY_PLAYER_NOTIFICATIONS_ENABLED)) {
send_text_message_printf(ses->client_channel, "$C4Leave: %zu/%" PRIu32 "\n%s", send_text_message_printf(ses->client_channel, "$C4Leave: %zu/%" PRIu32 "\n%s",
index, p.guild_card_number, p.name.c_str()); index, p.guild_card_number, name.c_str());
} }
p.guild_card_number = 0; p.guild_card_number = 0;
p.name.clear(); p.name.clear();
+13 -9
View File
@@ -1786,7 +1786,7 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
const auto& game_c = game->clients[x]; const auto& game_c = game->clients[x];
if (game_c.get()) { if (game_c.get()) {
auto player = game_c->character(); auto player = game_c->character();
string name = player->disp.name.decode(game_c->language()); string name = escape_player_name(player->disp.name.decode(game_c->language()));
if (game->is_ep3()) { if (game->is_ep3()) {
info += string_printf("%zu: $C6%s$C7 L%" PRIu32 "\n", info += string_printf("%zu: $C6%s$C7 L%" PRIu32 "\n",
x + 1, name.c_str(), player->disp.stats.level + 1); x + 1, name.c_str(), player->disp.stats.level + 1);
@@ -1808,16 +1808,16 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
bool cheats_enabled = game->check_flag(Lobby::Flag::CHEATS_ENABLED); bool cheats_enabled = game->check_flag(Lobby::Flag::CHEATS_ENABLED);
bool locked = !game->password.empty(); bool locked = !game->password.empty();
if (cheats_enabled && locked) { if (cheats_enabled && locked) {
info += "$C4Locked$C7, $C6cheats enabled$C7\n"; info += "$C4Locked$C7, $C6cheats on$C7\n";
} else if (cheats_enabled) { } else if (cheats_enabled) {
info += "$C6Cheats enabled$C7\n"; info += "$C6Cheats on$C7\n";
} else if (locked) { } else if (locked) {
info += "$C4Locked$C7\n"; info += "$C4Locked$C7\n";
} }
if (game->quest) { if (game->quest) {
info += (game->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS)) ? "$C6Quest: " : "$C4Quest: "; info += (game->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS)) ? "$C6Quest: " : "$C4Quest: ";
info += game->quest->name; info += remove_color(game->quest->name);
info += "\n"; info += "\n";
} else if (game->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS)) { } else if (game->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS)) {
info += "$C6Quest in progress\n"; info += "$C6Quest in progress\n";
@@ -1862,17 +1862,18 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
auto team = tourn->get_team(team_index); auto team = tourn->get_team(team_index);
if (team) { if (team) {
string message; string message;
if (team->name.empty()) { string team_name = escape_player_name(team->name);
if (team_name.empty()) {
message = "(No registrant)"; message = "(No registrant)";
} else if (team->max_players == 1) { } else if (team->max_players == 1) {
message = string_printf("$C6%s$C7\n%zu %s (%s)\nPlayers:", message = string_printf("$C6%s$C7\n%zu %s (%s)\nPlayers:",
team->name.c_str(), team_name.c_str(),
team->num_rounds_cleared, team->num_rounds_cleared,
team->num_rounds_cleared == 1 ? "win" : "wins", team->num_rounds_cleared == 1 ? "win" : "wins",
team->is_active ? "active" : "defeated"); team->is_active ? "active" : "defeated");
} else { } else {
message = string_printf("$C6%s$C7\n%zu %s (%s)%s\nPlayers:", message = string_printf("$C6%s$C7\n%zu %s (%s)%s\nPlayers:",
team->name.c_str(), team_name.c_str(),
team->num_rounds_cleared, team->num_rounds_cleared,
team->num_rounds_cleared == 1 ? "win" : "wins", team->num_rounds_cleared == 1 ? "win" : "wins",
team->is_active ? "active" : "defeated", team->is_active ? "active" : "defeated",
@@ -1883,10 +1884,13 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
if (player.player_name.empty()) { if (player.player_name.empty()) {
message += string_printf("\n $C6%08" PRIX32 "$C7", player.serial_number); message += string_printf("\n $C6%08" PRIX32 "$C7", player.serial_number);
} else { } else {
message += string_printf("\n $C6%s$C7 (%08" PRIX32 ")", player.player_name.c_str(), player.serial_number); string player_name = escape_player_name(player.player_name);
message += string_printf("\n $C6%s$C7 (%08" PRIX32 ")", player_name.c_str(), player.serial_number);
} }
} else { } else {
message += string_printf("\n $C3%s \"%s\"$C7", player.com_deck->player_name.c_str(), player.com_deck->deck_name.c_str()); string player_name = escape_player_name(player.com_deck->player_name);
string deck_name = escape_player_name(player.com_deck->deck_name);
message += string_printf("\n $C3%s \"%s\"$C7", player_name.c_str(), deck_name.c_str());
} }
} }
send_ship_info(c, message); send_ship_info(c, message);
+1 -1
View File
@@ -842,7 +842,7 @@ static void on_word_select_t(shared_ptr<Client> c, uint8_t command, uint8_t, voi
} }
} catch (const exception& e) { } catch (const exception& e) {
string name = c->character()->disp.name.decode(c->language()); string name = escape_player_name(c->character()->disp.name.decode(c->language()));
lc->log.warning("Untranslatable Word Select message: %s", e.what()); lc->log.warning("Untranslatable Word Select message: %s", e.what());
send_text_message_printf(lc, "$C4Untranslatable Word\nSelect message from\n%s", name.c_str()); send_text_message_printf(lc, "$C4Untranslatable Word\nSelect message from\n%s", name.c_str());
} }
+37 -1
View File
@@ -281,7 +281,6 @@ void add_color(StringWriter& w, const char* src, size_t max_input_chars) {
} }
src++; src++;
} }
w.put<char>(0);
} }
string add_color(const string& s) { string add_color(const string& s) {
@@ -290,6 +289,35 @@ string add_color(const string& s) {
return std::move(w.str()); return std::move(w.str());
} }
void remove_color(StringWriter& w, const char* src, size_t max_input_chars) {
for (size_t x = 0; (x < max_input_chars) && *src; x++) {
if (*src == '$') {
w.put<char>('%');
w.put<char>('s');
} else if (*src == '%') {
w.put<char>('%');
w.put<char>('%');
} else if (*src == '#') {
w.put<char>('%');
w.put<char>('n');
} else if (*src == '\t') {
w.put<char>('$');
} else if (*src == '\n') {
w.put<char>('#');
} else {
w.put<char>(*src);
}
src++;
}
w.put<char>(0);
}
string remove_color(const string& s) {
StringWriter w;
remove_color(w, s.data(), s.size());
return std::move(w.str());
}
string strip_color(const string& s) { string strip_color(const string& s) {
string ret; string ret;
for (size_t r = 0; r < s.size(); r++) { for (size_t r = 0; r < s.size(); r++) {
@@ -302,3 +330,11 @@ string strip_color(const string& s) {
} }
return ret; return ret;
} }
string escape_player_name(const string& name) {
if (name.size() > 2 && name[0] == '\t' && name[1] != 'C') {
return remove_color(name.substr(2));
} else {
return remove_color(name);
}
}
+7
View File
@@ -549,4 +549,11 @@ std::string add_color(const std::string& s);
size_t add_color_inplace(char* a, size_t max_chars); size_t add_color_inplace(char* a, size_t max_chars);
void add_color_inplace(std::string& s); void add_color_inplace(std::string& s);
// remove_color does the opposite of add_color (it changes \t into $, for
// example). strip_color is irreversible; it deletes color escape sequences.
void remove_color(StringWriter& w, const char* src, size_t max_input_chars);
std::string remove_color(const std::string& s);
std::string strip_color(const std::string& s); std::string strip_color(const std::string& s);
std::string escape_player_name(const std::string& name);