diff --git a/src/Http/Handlers/PostStartMatch.php b/src/Http/Handlers/PostStartMatch.php index ce076d3..d65dd6d 100644 --- a/src/Http/Handlers/PostStartMatch.php +++ b/src/Http/Handlers/PostStartMatch.php @@ -6,6 +6,7 @@ namespace BattleForge\Http\Handlers; use BattleForge\Application\ScenarioDraft; use BattleForge\Application\ScenarioSerializer; +use BattleForge\Application\TurnToken; use BattleForge\Domain\ScenarioValidator; use BattleForge\Http\CsrfToken; use BattleForge\Http\Request; @@ -36,6 +37,20 @@ final class PostStartMatch return Response::json(400, ['errors' => [$exception->getMessage()]]); } - return Response::json(200, ['match' => ScenarioSerializer::matchToArray($match)]); + $matchId = bin2hex(random_bytes(8)); + $matchArray = ScenarioSerializer::matchToArray($match); + $turnToken = TurnToken::issue( + $secret, + $matchId, + $match->activeTeamId, + $match->round, + count($match->actionLog), + ); + + return Response::json(200, [ + 'match' => $matchArray, + 'matchId' => $matchId, + 'turnToken' => $turnToken, + ]); } } diff --git a/tests/Integration/PostStartMatchTest.php b/tests/Integration/PostStartMatchTest.php index 1229f9c..3280014 100644 --- a/tests/Integration/PostStartMatchTest.php +++ b/tests/Integration/PostStartMatchTest.php @@ -38,6 +38,10 @@ final class PostStartMatchTest extends TestCase self::assertSame('alpha', $body['match']['activeTeamId'] ?? null); self::assertSame(1, $body['match']['round'] ?? null); self::assertCount(6, $body['match']['units'] ?? []); + self::assertIsString($body['matchId'] ?? null); + self::assertMatchesRegularExpression('/^[a-f0-9]{16,}$/', $body['matchId']); + self::assertIsString($body['turnToken'] ?? null); + self::assertMatchesRegularExpression('/^[a-f0-9]{32}$/', $body['turnToken']); } public function testItReturns400OnAnInvalidScenario(): void @@ -54,6 +58,33 @@ final class PostStartMatchTest extends TestCase self::assertSame(400, $response->status); } + public function testItReturnsATurnTokenValidForTheInitialMatchState(): void + { + [$token, $cookie] = CsrfToken::issue(self::SECRET); + $handler = new PostStartMatch(); + $request = $this->buildRequest( + rawBody: json_encode($this->validScenario(), JSON_THROW_ON_ERROR), + csrfHeader: $token, + cookies: ['__csrf' => $cookie], + ); + $response = $handler->handle($request, ['id' => 'demo']); + + self::assertSame(200, $response->status); + $body = json_decode($response->body, true); + $matchId = $body['matchId']; + $turnToken = $body['turnToken']; + $lastActionIndex = count($body['match']['actionLog'] ?? []); + + self::assertTrue(\BattleForge\Application\TurnToken::verify( + self::SECRET, + $matchId, + $body['match']['activeTeamId'], + $body['match']['round'], + $lastActionIndex, + $turnToken, + )); + } + /** @param array $cookies */ private function buildRequest(string $rawBody, string $csrfHeader, array $cookies = []): Request {