| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Integration\Admin;
- use App\Domain\Auth\Role;
- use App\Domain\Auth\TokenKind;
- use App\Tests\Integration\Support\AppTestCase;
- final class TokensControllerTest extends AppTestCase
- {
- public function testCreateReporterTokenReturnsRawOnce(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $reporterId = $this->createReporter('web-tokens');
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/tokens',
- ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'],
- json_encode(['kind' => 'reporter', 'reporter_id' => $reporterId]) ?: null,
- );
- self::assertSame(201, $resp->getStatusCode());
- $body = $this->decode($resp);
- self::assertSame('reporter', $body['kind']);
- self::assertSame($reporterId, $body['reporter_id']);
- self::assertArrayHasKey('raw_token', $body);
- self::assertStringStartsWith('irdb_rep_', (string) $body['raw_token']);
- // Second fetch via list must not include raw_token.
- $list = $this->request('GET', '/api/v1/admin/tokens', [
- 'Authorization' => 'Bearer ' . $admin,
- ]);
- $listBody = $this->decode($list);
- foreach ($listBody['data'] as $row) {
- self::assertArrayNotHasKey('raw_token', $row);
- }
- }
- public function testCreateAdminTokenRequiresRole(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/tokens',
- ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'],
- json_encode(['kind' => 'admin']) ?: null,
- );
- self::assertSame(400, $resp->getStatusCode());
- self::assertArrayHasKey('role', $this->decode($resp)['details']);
- }
- public function testServiceKindRefused(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/tokens',
- ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'],
- json_encode(['kind' => 'service']) ?: null,
- );
- self::assertSame(400, $resp->getStatusCode());
- }
- public function testListExcludesServiceTokens(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $this->createToken(TokenKind::Service);
- $resp = $this->request('GET', '/api/v1/admin/tokens', [
- 'Authorization' => 'Bearer ' . $admin,
- ]);
- $body = $this->decode($resp);
- foreach ($body['data'] as $row) {
- self::assertNotSame('service', $row['kind']);
- }
- }
- public function testRevokeMarksRevokedAt(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $reporterId = $this->createReporter('web-revoke');
- $created = $this->request(
- 'POST',
- '/api/v1/admin/tokens',
- ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'],
- json_encode(['kind' => 'reporter', 'reporter_id' => $reporterId]) ?: null,
- );
- $tokenId = (int) $this->decode($created)['id'];
- $delete = $this->request('DELETE', "/api/v1/admin/tokens/{$tokenId}", [
- 'Authorization' => 'Bearer ' . $admin,
- ]);
- self::assertSame(204, $delete->getStatusCode());
- $row = $this->db->fetchAssociative('SELECT revoked_at FROM api_tokens WHERE id = :id', ['id' => $tokenId]);
- self::assertIsArray($row);
- self::assertNotNull($row['revoked_at']);
- }
- public function testPurgeDeletesRevokedToken(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $reporterId = $this->createReporter('web-purge');
- $created = $this->request(
- 'POST',
- '/api/v1/admin/tokens',
- ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'],
- json_encode(['kind' => 'reporter', 'reporter_id' => $reporterId]) ?: null,
- );
- $tokenId = (int) $this->decode($created)['id'];
- // Revoke first.
- self::assertSame(204, $this->request('DELETE', "/api/v1/admin/tokens/{$tokenId}", [
- 'Authorization' => 'Bearer ' . $admin,
- ])->getStatusCode());
- $purge = $this->request('DELETE', "/api/v1/admin/tokens/{$tokenId}/purge", [
- 'Authorization' => 'Bearer ' . $admin,
- ]);
- self::assertSame(204, $purge->getStatusCode());
- $count = (int) $this->db->fetchOne('SELECT COUNT(*) FROM api_tokens WHERE id = :id', ['id' => $tokenId]);
- self::assertSame(0, $count);
- $audit = $this->db->fetchAssociative(
- "SELECT action, target_id FROM audit_log WHERE action = 'token.deleted' ORDER BY id DESC LIMIT 1"
- );
- self::assertIsArray($audit);
- self::assertSame((string) $tokenId, $audit['target_id']);
- }
- public function testPurgeRefusesActiveToken(): void
- {
- $admin = $this->createToken(TokenKind::Admin, role: Role::Admin);
- $reporterId = $this->createReporter('web-still-active');
- $created = $this->request(
- 'POST',
- '/api/v1/admin/tokens',
- ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'],
- json_encode(['kind' => 'reporter', 'reporter_id' => $reporterId]) ?: null,
- );
- $tokenId = (int) $this->decode($created)['id'];
- $purge = $this->request('DELETE', "/api/v1/admin/tokens/{$tokenId}/purge", [
- 'Authorization' => 'Bearer ' . $admin,
- ]);
- self::assertSame(409, $purge->getStatusCode());
- self::assertSame('not_revoked', $this->decode($purge)['error']);
- $count = (int) $this->db->fetchOne('SELECT COUNT(*) FROM api_tokens WHERE id = :id', ['id' => $tokenId]);
- self::assertSame(1, $count);
- }
- }
|