get(EntityManagerInterface::class); $user = new User(); $user->setEmail('test-attest-'.uniqid().'@example.com'); $user->setFirstName('Test'); $user->setLastName('User'); $user->setPassword('$2y$13$hashed'); $em->persist($user); $payout = new Payout(); $payout->setOrganizer($user); $payout->setStripePayoutId('po_check_'.uniqid()); $payout->setStatus('paid'); $payout->setAmount(10000); $payout->setCurrency('eur'); $em->persist($payout); $em->flush(); $client->request('GET', '/attestation/check/'.$payout->getStripePayoutId()); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'Attestation authentique'); } public function testCheckWithInvalidPayout(): void { $client = static::createClient(); $client->request('GET', '/attestation/check/po_fake_invalid'); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'Attestation introuvable'); } public function testVentesRefWithValidReference(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $user = new User(); $user->setEmail('test-vref-'.uniqid().'@example.com'); $user->setFirstName('Test'); $user->setLastName('User'); $user->setPassword('$2y$13$hashed'); $em->persist($user); $event = new Event(); $event->setAccount($user); $event->setTitle('Test Event'); $event->setStartAt(new \DateTimeImmutable('+1 day')); $event->setEndAt(new \DateTimeImmutable('+2 days')); $event->setAddress('123 Rue Test'); $event->setZipcode('75001'); $event->setCity('Paris'); $em->persist($event); $reference = 'REF-'.uniqid(); $payload = [ 'ref' => $reference, 'event' => 'Test Event', 'organizer' => 'Test User', 'generatedAt' => '01/04/2026 10:00:00', 'totalSold' => 10, 'billets' => [], 'categories' => [], ]; $attestation = new Attestation($reference, 'sig_'.uniqid(), $event, $user, 10, $payload); $em->persist($attestation); $em->flush(); $client->request('GET', '/attestation/ventes/r/'.$reference); self::assertResponseIsSuccessful(); } public function testVentesRefWithInvalidReference(): void { $client = static::createClient(); $client->request('GET', '/attestation/ventes/r/INVALID_REF'); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'introuvable'); } public function testVentesWithValidHash(): void { $client = static::createClient(); $appSecret = static::getContainer()->getParameter('kernel.secret'); $data = ['event' => 'Test Event', 'total' => 5000]; $hash = AttestationController::generateHash($data, $appSecret); $client->request('GET', '/attestation/ventes/'.$hash); self::assertResponseIsSuccessful(); } public function testVentesWithValidHashAndRegisteredAttestation(): void { $client = static::createClient(); $em = static::getContainer()->get(EntityManagerInterface::class); $appSecret = static::getContainer()->getParameter('kernel.secret'); $user = new User(); $user->setEmail('test-vreg-'.uniqid().'@example.com'); $user->setFirstName('Test'); $user->setLastName('User'); $user->setPassword('$2y$13$hashed'); $em->persist($user); $event = new Event(); $event->setAccount($user); $event->setTitle('Test Event'); $event->setStartAt(new \DateTimeImmutable('+1 day')); $event->setEndAt(new \DateTimeImmutable('+2 days')); $event->setAddress('123 Rue Test'); $event->setZipcode('75001'); $event->setCity('Paris'); $em->persist($event); $ref = 'REF-'.uniqid(); $data = [ 'ref' => $ref, 'event' => 'Registered Event', 'organizer' => 'Test User', 'generatedAt' => '01/04/2026 10:00:00', 'totalSold' => 20, 'billets' => [], 'categories' => [], ]; $json = json_encode($data, \JSON_UNESCAPED_UNICODE); $signatureHash = hash_hmac('sha256', $json, $appSecret); $attestation = new Attestation($ref, $signatureHash, $event, $user, 20, $data); $em->persist($attestation); $em->flush(); $hash = AttestationController::generateHash($data, $appSecret); $client->request('GET', '/attestation/ventes/'.$hash); self::assertResponseIsSuccessful(); } public function testVentesWithInvalidBase64(): void { $client = static::createClient(); $client->request('GET', '/attestation/ventes/!!!invalid-base64!!!'); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'introuvable'); } public function testVentesWithMissingPipeSeparator(): void { $client = static::createClient(); $hash = rtrim(strtr(base64_encode('no-pipe-here'), '+/', '-_'), '='); $client->request('GET', '/attestation/ventes/'.$hash); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'introuvable'); } public function testVentesWithInvalidSignature(): void { $client = static::createClient(); $json = json_encode(['event' => 'Test'], \JSON_UNESCAPED_UNICODE); $hash = rtrim(strtr(base64_encode('invalidsignature|'.$json), '+/', '-_'), '='); $client->request('GET', '/attestation/ventes/'.$hash); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'introuvable'); } public function testVentesWithInvalidJsonPayload(): void { $client = static::createClient(); $appSecret = static::getContainer()->getParameter('kernel.secret'); $invalidJson = '{invalid json}'; $signature = hash_hmac('sha256', $invalidJson, $appSecret); $hash = rtrim(strtr(base64_encode($signature.'|'.$invalidJson), '+/', '-_'), '='); $client->request('GET', '/attestation/ventes/'.$hash); self::assertResponseIsSuccessful(); self::assertSelectorTextContains('body', 'introuvable'); } public function testGenerateHash(): void { $data = ['key' => 'value', 'amount' => 1000]; $secret = 'test-secret'; $hash = AttestationController::generateHash($data, $secret); self::assertNotEmpty($hash); self::assertMatchesRegularExpression('/^[A-Za-z0-9\-_]+$/', $hash); $decoded = base64_decode(strtr($hash, '-_', '+/'), true); self::assertNotFalse($decoded); $parts = explode('|', $decoded, 2); self::assertCount(2, $parts); [$signature, $jsonPayload] = $parts; $expectedSignature = hash_hmac('sha256', $jsonPayload, $secret); self::assertTrue(hash_equals($expectedSignature, $signature)); self::assertSame($data, json_decode($jsonPayload, true)); } public function testGenerateHashWithUnicodeData(): void { $data = ['name' => 'Événement été', 'city' => 'Zürich']; $secret = 'test-secret'; $hash = AttestationController::generateHash($data, $secret); $decoded = base64_decode(strtr($hash, '-_', '+/'), true); $parts = explode('|', $decoded, 2); self::assertStringContainsString('Événement été', $parts[1]); self::assertStringContainsString('Zürich', $parts[1]); } }