1
0

TokenIssuerTest.php 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Tests\Unit\Auth;
  4. use App\Domain\Auth\Token;
  5. use App\Domain\Auth\TokenIssuer;
  6. use App\Domain\Auth\TokenKind;
  7. use PHPUnit\Framework\TestCase;
  8. final class TokenIssuerTest extends TestCase
  9. {
  10. public function testIssuedTokenMatchesFormat(): void
  11. {
  12. $issuer = new TokenIssuer();
  13. foreach (TokenKind::cases() as $kind) {
  14. $raw = $issuer->issue($kind);
  15. self::assertSame(1, preg_match('/^irdb_(rep|con|adm|svc)_[A-Z2-7]{32}$/', $raw), "format mismatch for {$kind->value}: {$raw}");
  16. self::assertStringStartsWith('irdb_' . $kind->code() . '_', $raw);
  17. }
  18. }
  19. public function testIssuedTokensAreUnique(): void
  20. {
  21. $issuer = new TokenIssuer();
  22. $set = [];
  23. for ($i = 0; $i < 50; ++$i) {
  24. $set[$issuer->issue(TokenKind::Admin)] = true;
  25. }
  26. self::assertCount(50, $set);
  27. }
  28. public function testIssuedTokenRoundTripsThroughParse(): void
  29. {
  30. $issuer = new TokenIssuer();
  31. foreach (TokenKind::cases() as $kind) {
  32. $raw = $issuer->issue($kind);
  33. $parsed = Token::parse($raw);
  34. self::assertNotNull($parsed, "parse failed for {$raw}");
  35. self::assertSame($kind, $parsed->kind);
  36. self::assertSame($raw, $parsed->raw);
  37. }
  38. }
  39. public function testIssuedBodyAlwaysExactlyThirtyTwoBase32Chars(): void
  40. {
  41. // SEC_REVIEW F39: 20 bytes (160 bits) divides exactly by 5 → 32
  42. // base32 chars with zero trailing-bit ambiguity. The previous dead
  43. // `str_pad` branch in `base32Encode` (which prompted the F39
  44. // finding) is gone, but the property it implied — every char
  45. // carries 5 useful bits — must hold across many random samples.
  46. $issuer = new TokenIssuer();
  47. for ($i = 0; $i < 100; ++$i) {
  48. $raw = $issuer->issue(TokenKind::Admin);
  49. $body = substr($raw, strlen('irdb_adm_'));
  50. self::assertSame(32, strlen($body), "issued body must be 32 chars: {$raw}");
  51. self::assertSame(1, preg_match('/^[A-Z2-7]{32}$/', $body), "issued body must use canonical base32: {$raw}");
  52. }
  53. }
  54. }