From 81bee3ff229084a30cdb8b657dba7b4720272f43 Mon Sep 17 00:00:00 2001 From: alallema Date: Wed, 23 Feb 2022 16:16:12 +0100 Subject: [PATCH] Adding some validations --- src/Delegates/HandlesSystem.php | 17 ++++- src/Exceptions/InvalidArgumentException.php | 10 +++ tests/Endpoints/TenantTokenTest.php | 72 ++++++++++++--------- 3 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/Delegates/HandlesSystem.php b/src/Delegates/HandlesSystem.php index f5ce70e3a..20536213d 100644 --- a/src/Delegates/HandlesSystem.php +++ b/src/Delegates/HandlesSystem.php @@ -4,6 +4,8 @@ namespace MeiliSearch\Delegates; +use DateTime; +use MeiliSearch\Exceptions\InvalidArgumentException; use MeiliSearch\Http\Serialize\Json; trait HandlesSystem @@ -39,8 +41,19 @@ public function base64url_encode($data) return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } - public function generateTenantToken($searchRules, ?int $expiresAt = null, ?string $apiKey = null): string + public function generateTenantToken($searchRules, ?DateTime $expiresAt = null, ?string $apiKey = null): string { + // Validate every fields + if (null == $apiKey && null == $this->apiKey) { + throw InvalidArgumentException::emptyArgument('api key'); + } + if (null == $searchRules) { + throw InvalidArgumentException::emptyArgument('search rules'); + } + if ($expiresAt && new DateTime() > $expiresAt) { + throw InvalidArgumentException::dateIsExpired($expiresAt); + } + $json = new Json(); // Standard JWT header for encryption with SHA256/HS256 algorithm @@ -57,7 +70,7 @@ public function generateTenantToken($searchRules, ?int $expiresAt = null, ?strin $payload['apiKeyPrefix'] = substr($apiKey, 0, 8); $payload['searchRules'] = $searchRules; if ($expiresAt) { - $payload['exp'] = $expiresAt; + $payload['exp'] = $expiresAt->getTimestamp(); } // Serialize the Header diff --git a/src/Exceptions/InvalidArgumentException.php b/src/Exceptions/InvalidArgumentException.php index 5ebd3dad4..55b7cc965 100644 --- a/src/Exceptions/InvalidArgumentException.php +++ b/src/Exceptions/InvalidArgumentException.php @@ -4,6 +4,7 @@ namespace MeiliSearch\Exceptions; +use DateTime; use Exception; final class InvalidArgumentException extends Exception @@ -25,4 +26,13 @@ public static function emptyArgument(string $argumentName): self null ); } + + public static function dateIsExpired(DateTime $date): self + { + return new self( + sprintf('DateTime "%s" is expired. The date expiresAt should be in the future.', $date->format('Y-m-d H:i:s')), + 400, + null + ); + } } diff --git a/tests/Endpoints/TenantTokenTest.php b/tests/Endpoints/TenantTokenTest.php index e3030272e..0b7c8d193 100644 --- a/tests/Endpoints/TenantTokenTest.php +++ b/tests/Endpoints/TenantTokenTest.php @@ -4,11 +4,11 @@ namespace Tests\Endpoints; -use DateTimeInterface; -use Tests\TestCase; +use Datetime; use MeiliSearch\Client; use MeiliSearch\Exceptions\ApiException; -use \Datetime; +use MeiliSearch\Exceptions\InvalidArgumentException; +use Tests\TestCase; final class TenantTokenTest extends TestCase { @@ -18,9 +18,7 @@ final class TenantTokenTest extends TestCase protected function setUp(): void { parent::setUp(); - $index = $this->createEmptyIndex('tenantToken'); - $promise = $index->addDocuments(self::DOCUMENTS); - $index->waitForTask($promise['uid']); + $this->createEmptyIndex('tenantToken'); $response = $this->client->getKeys(); $this->privateKey = array_reduce($response['results'], function ($carry, $item) { @@ -33,7 +31,12 @@ protected function setUp(): void public function testGenerateTenantTokenWithSearchRulesOnly(): void { - $token = $this->privateClient->generateTenantToken(searchRules: array('*')); + $promise = $this->client->index('tenantToken')->addDocuments(self::DOCUMENTS); + $this->client->waitForTask($promise['uid']); + + $token = $this->privateClient->generateTenantToken( + searchRules: ['*'] + ); $tokenClient = new Client('http://127.0.0.1:7700', $token); $response = $tokenClient->index('tenantToken')->search(''); @@ -46,9 +49,22 @@ public function testGenerateTenantTokenWithSearchRulesOnly(): void $this->assertCount(7, $response->getHits()); } + public function testGenerateTenantTokenWithSearchRulesOnOneIndex(): void + { + $this->createEmptyIndex('tenantTokenDuplicate'); + $token = $this->privateClient->generateTenantToken(searchRules: ['tenantToken']); + $tokenClient = new Client('http://127.0.0.1:7700', $token); + $response = $tokenClient->index('tenantToken')->search(''); + + $this->assertArrayHasKey('hits', $response->toArray()); + $this->assertArrayHasKey('query', $response->toArray()); + $this->expectException(ApiException::class); + $response = $tokenClient->index('tenantTokenDuplicate')->search(''); + } + public function testGenerateTenantTokenWithApiKey(): void { - $token = $this->client->generateTenantToken(searchRules: array('*'), apiKey: $this->privateKey); + $token = $this->client->generateTenantToken(searchRules: ['*'], apiKey: $this->privateKey); $tokenClient = new Client('http://127.0.0.1:7700', $token); $response = $tokenClient->index('tenantToken')->search(''); @@ -57,16 +73,14 @@ public function testGenerateTenantTokenWithApiKey(): void $this->assertArrayHasKey('limit', $response->toArray()); $this->assertArrayHasKey('processingTimeMs', $response->toArray()); $this->assertArrayHasKey('query', $response->toArray()); - $this->assertSame(7, $response->getNbHits()); - $this->assertCount(7, $response->getHits()); } public function testGenerateTenantTokenWithExpiresAt(): void { $date = new DateTime(); - $tomorrow = $date->modify('+1 day')->getTimestamp(); + $tomorrow = $date->modify('+1 day'); - $token = $this->privateClient->generateTenantToken(searchRules: array('*'), expiresAt: $tomorrow); + $token = $this->privateClient->generateTenantToken(searchRules: ['*'], expiresAt: $tomorrow); $tokenClient = new Client('http://127.0.0.1:7700', $token); $response = $tokenClient->index('tenantToken')->search(''); @@ -75,39 +89,33 @@ public function testGenerateTenantTokenWithExpiresAt(): void $this->assertArrayHasKey('limit', $response->toArray()); $this->assertArrayHasKey('processingTimeMs', $response->toArray()); $this->assertArrayHasKey('query', $response->toArray()); - $this->assertSame(7, $response->getNbHits()); - $this->assertCount(7, $response->getHits()); } - - public function testGenerateTenantTokenWithoutSearchRules(): void + public function testGenerateTenantTokenWithEmptySearchRules(): void { + $this->expectException(InvalidArgumentException::class); $token = $this->privateClient->generateTenantToken(searchRules: ''); - $tokenClient = new Client('http://127.0.0.1:7700', $token); - - $this->expectException(ApiException::class); - $tokenClient->index('tenantToken')->search(''); } - - public function testGenerateTenantTokenWithMasterKey(): void + public function testGenerateTenantTokenWithSearchRulesEmptyArray(): void { - $token = $this->client->generateTenantToken(array('*')); - $tokenClient = new Client('http://127.0.0.1:7700', $token); - - $this->expectException(ApiException::class); - $tokenClient->index('tenantToken')->search(''); + $this->expectException(InvalidArgumentException::class); + $token = $this->privateClient->generateTenantToken(searchRules: []); } public function testGenerateTenantTokenWithBadExpiresAt(): void { $date = new DateTime(); - $yesterday = $date->modify('-2 day')->getTimestamp(); + $yesterday = $date->modify('-1 day'); - $token = $this->privateClient->generateTenantToken(searchRules: array('*'), expiresAt: $yesterday); - $tokenClient = new Client('http://127.0.0.1:7700', $token); + $this->expectException(InvalidArgumentException::class); + $token = $this->privateClient->generateTenantToken(searchRules: ['*'], expiresAt: $yesterday); + } - $this->expectException(ApiException::class); - $tokenClient->index('tenantToken')->search(''); + public function testGenerateTenantTokenWithNoApiKey(): void + { + $client = new Client($this->host); + $this->expectException(InvalidArgumentException::class); + $token = $client->generateTenantToken(searchRules: ['*']); } }