diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 6edf3c4..ce58ce4 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -7,6 +7,7 @@ object Log4j2 { const val api = "$group:log4j-api:$version" const val core = "$group:log4j-core:$version" const val slf4j = "$group:log4j-slf4j-impl:$version" + const val jul = "$group:log4j-jul:$version" } object Lombok { @@ -86,7 +87,7 @@ object JavaWebSocket { } object SpringBoot { - const val version = "2.6.1" + const val version = "2.6.2" const val group = "org.springframework.boot" const val plugin = group const val starterWebsocket = "$group:spring-boot-starter-websocket" diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java new file mode 100644 index 0000000..b706d0a --- /dev/null +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java @@ -0,0 +1,53 @@ +package eu.jonahbauer.wizard.core.machine.states; + +import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage; +import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage; +import eu.jonahbauer.wizard.common.messages.player.ContinueMessage; +import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; +import eu.jonahbauer.wizard.core.machine.Game; +import eu.jonahbauer.wizard.core.machine.GameState; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC; +import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS; + +public abstract class SyncState extends GameState { + private final transient Set ready = new HashSet<>(); + + public SyncState(GameData data) { + super(data); + } + + @Override + public Optional onEnter(Game game) { + game.notify(new UserInputMessage(null, SYNC, getSyncTimeout(game, true))); + return syncTimeout(game); + } + + @Override + public Optional onMessage(Game game, UUID player, PlayerMessage message) { + if (message instanceof ContinueMessage) { + ready.add(player); + + if (ready.size() == get(PLAYERS).size()) { + return Optional.of(getNextState()); + } else { + return Optional.empty(); + } + } else { + return super.onMessage(game, player, message); + } + } + + @Override + public Optional onTimeout(Game game) { + game.notify(new TimeoutMessage()); + return Optional.of(getNextState()); + } + + protected abstract GameState getNextState(); +} diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java index 0c9ccf1..f4f9e01 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java @@ -103,6 +103,6 @@ public final class DeterminingTrump extends RoundState { } else { game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit)); } - return transition(new Predicting(data)); + return transition(new TrumpDetermined(data)); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/RoundState.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/RoundState.java index 02f822b..b261c88 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/RoundState.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/RoundState.java @@ -8,8 +8,12 @@ import java.util.UUID; import static eu.jonahbauer.wizard.core.machine.states.GameData.*; public abstract class RoundState extends GameState { + public static GameData requirements(GameData data) { + return data.require(PLAYERS, ROUND, SCORE); + } + public RoundState(GameData data) { - super(data.require(PLAYERS, ROUND, SCORE)); + super(requirements(data)); } protected UUID getDealer() { diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java index 2ab2e49..a60ca8a 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java @@ -1,52 +1,17 @@ package eu.jonahbauer.wizard.core.machine.states.round; -import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage; -import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage; -import eu.jonahbauer.wizard.common.messages.player.ContinueMessage; -import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; -import eu.jonahbauer.wizard.core.machine.Game; import eu.jonahbauer.wizard.core.machine.GameState; import eu.jonahbauer.wizard.core.machine.states.GameData; +import eu.jonahbauer.wizard.core.machine.states.SyncState; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; - -import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC; -import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS; - -public final class StartingRound extends RoundState { - private final transient Set ready = new HashSet<>(); +public final class StartingRound extends SyncState { public StartingRound(GameData data) { - super(data); - } - - @Override - public Optional onEnter(Game game) { - game.notify(new UserInputMessage(null, SYNC, getSyncTimeout(game, true))); - return syncTimeout(game); - } - - @Override - public Optional onMessage(Game game, UUID player, PlayerMessage message) { - if (message instanceof ContinueMessage) { - ready.add(player); - - if (ready.size() == get(PLAYERS).size()) { - return Optional.of(new Dealing(getData())); - } else { - return Optional.empty(); - } - } else { - return super.onMessage(game, player, message); - } + super(RoundState.requirements(data)); } @Override - public Optional onTimeout(Game game) { - game.notify(new TimeoutMessage()); - return Optional.of(new Dealing(getData())); + protected GameState getNextState() { + return new Dealing(getData()); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java new file mode 100644 index 0000000..efae7a4 --- /dev/null +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java @@ -0,0 +1,19 @@ +package eu.jonahbauer.wizard.core.machine.states.round; + +import eu.jonahbauer.wizard.core.machine.GameState; +import eu.jonahbauer.wizard.core.machine.states.GameData; +import eu.jonahbauer.wizard.core.machine.states.SyncState; + +import static eu.jonahbauer.wizard.core.machine.states.GameData.*; + +public final class TrumpDetermined extends SyncState { + + public TrumpDetermined(GameData data) { + super(RoundState.requirements(data).requireEach(PLAYERS, HANDS).require(PREDICTIONS, TRUMP_SUIT, CURRENT_PLAYER)); + } + + @Override + protected GameState getNextState() { + return new Predicting(getData()); + } +} diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java index ed98858..1b75870 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java @@ -1,52 +1,18 @@ package eu.jonahbauer.wizard.core.machine.states.trick; -import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage; -import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage; -import eu.jonahbauer.wizard.common.messages.player.ContinueMessage; -import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; -import eu.jonahbauer.wizard.core.machine.Game; -import eu.jonahbauer.wizard.core.machine.states.GameData; import eu.jonahbauer.wizard.core.machine.GameState; +import eu.jonahbauer.wizard.core.machine.states.GameData; +import eu.jonahbauer.wizard.core.machine.states.SyncState; +import eu.jonahbauer.wizard.core.machine.states.round.RoundState; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; - -import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC; -import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS; - -public final class StartingTrick extends TrickState { - private final transient Set ready = new HashSet<>(); +public final class StartingTrick extends SyncState { public StartingTrick(GameData data) { - super(data); - } - - @Override - public Optional onEnter(Game game) { - game.notify(new UserInputMessage(null, SYNC, getSyncTimeout(game, true))); - return syncTimeout(game); - } - - @Override - public Optional onMessage(Game game, UUID player, PlayerMessage message) { - if (message instanceof ContinueMessage) { - ready.add(player); - - if (ready.size() == get(PLAYERS).size()) { - return Optional.of(new PlayingCard(getData())); - } else { - return Optional.empty(); - } - } else { - return super.onMessage(game, player, message); - } + super(RoundState.requirements(TrickState.requirements(data))); } @Override - public Optional onTimeout(Game game) { - game.notify(new TimeoutMessage()); - return Optional.of(new PlayingCard(getData())); + protected GameState getNextState() { + return new PlayingCard(getData()); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/TrickState.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/TrickState.java index b5a4241..4102172 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/TrickState.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/TrickState.java @@ -6,12 +6,14 @@ import eu.jonahbauer.wizard.core.machine.states.round.RoundState; import static eu.jonahbauer.wizard.core.machine.states.GameData.*; public abstract class TrickState extends RoundState { + public static GameData requirements(GameData data) { + return data.requireEach(PLAYERS, HANDS) + .requireEach(PLAYERS, PREDICTIONS) + .require(TRUMP_SUIT, TRICK, TRICKS, CURRENT_PLAYER) + .keep(CLOUDED_PLAYER); + } + public TrickState(GameData data) { - super( - data.requireEach(PLAYERS, HANDS) - .requireEach(PLAYERS, PREDICTIONS) - .require(TRUMP_SUIT, TRICK, TRICKS, CURRENT_PLAYER) - .keep(CLOUDED_PLAYER) - ); + super(requirements(data)); } } diff --git a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java index f750e12..be99ac6 100644 --- a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java +++ b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java @@ -38,7 +38,7 @@ public class DeterminingTrumpTest { @SuppressWarnings("SameParameterValue") private Game performTest(GameConfiguration configuration, int round, Map> hands, Card trumpCard, MessageQueue queue) { Game game = spy(new Game(configuration, queue)); - doFinish().when(game).transition(any(Predicting.class)); + doFinish().when(game).transition(any(TrumpDetermined.class)); queue.setGame(game); var playerList = List.of(players); @@ -76,7 +76,7 @@ public class DeterminingTrumpTest { InOrder order = inOrder(game); order.verify(game).notify(any(StateMessage.class)); // determining trump order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.YELLOW_1 && trump.getSuit() == Card.Suit.YELLOW)); - order.verify(game).transition(any(Predicting.class)); // round is finished + order.verify(game).transition(any(TrumpDetermined.class)); // round is finished order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); @@ -100,7 +100,7 @@ public class DeterminingTrumpTest { InOrder order = inOrder(game); order.verify(game).notify(any(StateMessage.class)); // determining trump order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.GREEN_JESTER && trump.getSuit() == Card.Suit.NONE)); - order.verify(game).transition(any(Predicting.class)); + order.verify(game).transition(any(TrumpDetermined.class)); order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); @@ -127,7 +127,7 @@ public class DeterminingTrumpTest { order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.BLUE_WIZARD && trump.getSuit() == null)); order.verify(game).notify(any(UserInputMessage.class)); // user input request order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.BLUE_WIZARD && trump.getSuit() == Card.Suit.GREEN)); - order.verify(game).transition(any(Predicting.class)); + order.verify(game).transition(any(TrumpDetermined.class)); order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); @@ -156,7 +156,7 @@ public class DeterminingTrumpTest { order.verify(game).notify(any(UserInputMessage.class)); // user input request order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.WEREWOLF && trump.getSuit() == Card.Suit.YELLOW)); order.verify(game).notify(eq(players[3]), any(HandMessage.class)); // swap trump card and werewolf - order.verify(game).transition(any(Predicting.class)); + order.verify(game).transition(any(TrumpDetermined.class)); order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); diff --git a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java index 89012d2..87aab6b 100644 --- a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java +++ b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java @@ -55,6 +55,7 @@ public class RoundTest { @Test public void run_Simple() throws ExecutionException, InterruptedException { MessageQueue queue = new MessageQueue() + .sync(players) .sync(players) .addPrediction(players[3], 3) .addPrediction(players[0], 0) @@ -113,6 +114,7 @@ public class RoundTest { order.verify(game, atLeast(4)).notify(any(), any(HandMessage.class)); // hands order.verify(game).notify(any(StateMessage.class)); // determining_trump order.verify(game).notify(any(TrumpMessage.class)); // trump + order.verify(game).notify(any(StateMessage.class)); // trump_determined for (int i = 0; i < players.length; i++) { order.verify(game).notify(any(StateMessage.class)); // predicting order.verify(game).notify(any(UserInputMessage.class)); // user input @@ -148,6 +150,7 @@ public class RoundTest { MessageQueue queue = new MessageQueue() .sync(players) .addPickTrump(players[2], Card.Suit.YELLOW) + .sync(players) .addPrediction(players[3], 2) .addPrediction(players[0], 2) .addPrediction(players[1], 2) @@ -237,8 +240,9 @@ public class RoundTest { order.verify(game).notify(any(StateMessage.class)); // determining trump order.verify(game, times(2)).notify(any(TrumpMessage.class)); // werewolf order.verify(game).notify(any(UserInputMessage.class)); // user input - order.verify(game).notify(any(TrumpMessage.class)); // user input + order.verify(game).notify(any(TrumpMessage.class)); // trump order.verify(game).notify(any(), any(HandMessage.class)); // update hand + order.verify(game).notify(any(StateMessage.class)); // trump_determined for (int i = 0; i < players.length; i++) { order.verify(game).notify(any(StateMessage.class)); order.verify(game).notify(any(UserInputMessage.class)); diff --git a/wizard-server/build.gradle.kts b/wizard-server/build.gradle.kts index b00050a..7428307 100644 --- a/wizard-server/build.gradle.kts +++ b/wizard-server/build.gradle.kts @@ -15,4 +15,10 @@ dependencies { } implementation(SpringBoot.starterLog4j2) providedRuntime(SpringBoot.starterTomcat) + + // override vulnerable dependencies from spring-boot-starter-log4j2 + implementation(Log4j2.api) + implementation(Log4j2.core) + implementation(Log4j2.slf4j) + implementation(Log4j2.jul) }