Fix emoji exploit (#640)

This should fix the exploit that allows players to send custom text as
an "emoji". It does this by introducing a emoji ID (index into the emoji
table) instead of sending the raw emoji as a string.

- [ ] I have added screenshots for all UI updates
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [X] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors
regression is found:
PilkeySEK
This commit is contained in:
PilkeySEK
2025-05-02 07:46:14 -07:00
committed by evan
parent 4f081dbd36
commit 3ece10c86a
8 changed files with 57 additions and 34 deletions
+6 -3
View File
@@ -7,6 +7,7 @@ import {
PlayerID,
PlayerType,
} from "../game/Game";
import { flattenedEmojiTable } from "../Util";
export class EmojiExecution implements Execution {
private requestor: Player;
@@ -17,7 +18,7 @@ export class EmojiExecution implements Execution {
constructor(
private senderID: PlayerID,
private recipientID: PlayerID | typeof AllPlayers,
private emoji: string,
private emoji: number,
) {}
init(mg: Game, ticks: number): void {
@@ -38,10 +39,12 @@ export class EmojiExecution implements Execution {
}
tick(ticks: number): void {
const emojiString = flattenedEmojiTable.at(this.emoji);
if (this.requestor.canSendEmoji(this.recipient)) {
this.requestor.sendEmoji(this.recipient, this.emoji);
this.requestor.sendEmoji(this.recipient, emojiString);
if (
this.emoji == "🖕" &&
emojiString == "🖕" &&
this.recipient != AllPlayers &&
this.recipient.type() == PlayerType.FakeHuman
) {
+4 -2
View File
@@ -17,7 +17,7 @@ import {
import { euclDistFN, manhattanDistFN, TileRef } from "../game/GameMap";
import { PseudoRandom } from "../PseudoRandom";
import { GameID } from "../Schemas";
import { calculateBoundingBox, simpleHash } from "../Util";
import { calculateBoundingBox, flattenedEmojiTable, simpleHash } from "../Util";
import { ConstructionExecution } from "./ConstructionExecution";
import { EmojiExecution } from "./EmojiExecution";
import { NukeExecution } from "./NukeExecution";
@@ -38,6 +38,7 @@ export class FakeHumanExecution implements Execution {
private lastEmojiSent = new Map<Player, Tick>();
private lastNukeSent: [Tick, TileRef][] = [];
private embargoMalusApplied = new Set<PlayerID>();
private heckleEmoji: number[];
constructor(
gameID: GameID,
@@ -46,6 +47,7 @@ export class FakeHumanExecution implements Execution {
this.random = new PseudoRandom(
simpleHash(playerInfo.id) + simpleHash(gameID),
);
this.heckleEmoji = ["🤡", "😡"].map((e) => flattenedEmojiTable.indexOf(e));
}
init(mg: Game) {
@@ -248,7 +250,7 @@ export class FakeHumanExecution implements Execution {
new EmojiExecution(
this.player.id(),
enemy.id(),
this.random.randElement(["🤡", "😡"]),
this.random.randElement(this.heckleEmoji),
),
);
}
+8 -3
View File
@@ -8,6 +8,7 @@ import {
Tick,
} from "../../game/Game";
import { PseudoRandom } from "../../PseudoRandom";
import { flattenedEmojiTable } from "../../Util";
import { AttackExecution } from "../AttackExecution";
import { EmojiExecution } from "../EmojiExecution";
@@ -15,12 +16,16 @@ export class BotBehavior {
private enemy: Player | null = null;
private enemyUpdated: Tick;
private assistAcceptEmoji: number;
constructor(
private random: PseudoRandom,
private game: Game,
private player: Player,
private attackRatio: number,
) {}
) {
this.assistAcceptEmoji = flattenedEmojiTable.indexOf("👍");
}
handleAllianceRequests() {
for (const req of this.player.incomingAllianceRequests()) {
@@ -32,7 +37,7 @@ export class BotBehavior {
}
}
private emoji(player: Player, emoji: string) {
private emoji(player: Player, emoji: number) {
if (player.type() !== PlayerType.Human) return;
this.game.addExecution(
new EmojiExecution(this.player.id(), player.id(), emoji),
@@ -59,7 +64,7 @@ export class BotBehavior {
this.player.updateRelation(ally, -20);
this.enemy = target;
this.enemyUpdated = this.game.ticks();
this.emoji(ally, "👍");
this.emoji(ally, this.assistAcceptEmoji);
break outer;
}
}