Merge pull request #2248 from acelaya-forks/feature/api-key-simplification

Simplify ApiKey entity by exposing key as a readonly prop
This commit is contained in:
Alejandro Celaya 2024-11-04 23:17:17 +01:00 committed by GitHub
commit e4fe7adf00
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 28 additions and 46 deletions

View File

@ -109,7 +109,7 @@ class GenerateKeyCommand extends Command
)); ));
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$io->success(sprintf('Generated API key: "%s"', $apiKey->toString())); $io->success(sprintf('Generated API key: "%s"', $apiKey->key));
if (! ApiKey::isAdmin($apiKey)) { if (! ApiKey::isAdmin($apiKey)) {
ShlinkTable::default($io)->render( ShlinkTable::default($io)->render(

View File

@ -54,7 +54,7 @@ class ListKeysCommand extends Command
$messagePattern = $this->determineMessagePattern($apiKey); $messagePattern = $this->determineMessagePattern($apiKey);
// Set columns for this row // Set columns for this row
$rowData = [sprintf($messagePattern, $apiKey), sprintf($messagePattern, $apiKey->name ?? '-')]; $rowData = [sprintf($messagePattern, $apiKey->key), sprintf($messagePattern, $apiKey->name ?? '-')];
if (! $enabledOnly) { if (! $enabledOnly) {
$rowData[] = sprintf($messagePattern, $this->getEnabledSymbol($apiKey)); $rowData[] = sprintf($messagePattern, $this->getEnabledSymbol($apiKey));
} }

View File

@ -244,7 +244,7 @@ class ListShortUrlsCommand extends Command
} }
if ($input->getOption('show-api-key')) { if ($input->getOption('show-api-key')) {
$columnsMap['API Key'] = static fn (array $_, ShortUrl $shortUrl): string => $columnsMap['API Key'] = static fn (array $_, ShortUrl $shortUrl): string =>
$shortUrl->authorApiKey?->__toString() ?? ''; $shortUrl->authorApiKey?->key ?? '';
} }
if ($input->getOption('show-api-key-name')) { if ($input->getOption('show-api-key-name')) {
$columnsMap['API Key Name'] = static fn (array $_, ShortUrl $shortUrl): string|null => $columnsMap['API Key Name'] = static fn (array $_, ShortUrl $shortUrl): string|null =>

View File

@ -55,11 +55,11 @@ class ListKeysCommandTest extends TestCase
+--------------------------------------+------+------------+---------------------------+-------+ +--------------------------------------+------+------------+---------------------------+-------+
| Key | Name | Is enabled | Expiration date | Roles | | Key | Name | Is enabled | Expiration date | Roles |
+--------------------------------------+------+------------+---------------------------+-------+ +--------------------------------------+------+------------+---------------------------+-------+
| {$apiKey1} | - | --- | - | Admin | | {$apiKey1->key} | - | --- | - | Admin |
+--------------------------------------+------+------------+---------------------------+-------+ +--------------------------------------+------+------------+---------------------------+-------+
| {$apiKey2} | - | --- | 2020-01-01T00:00:00+00:00 | Admin | | {$apiKey2->key} | - | --- | 2020-01-01T00:00:00+00:00 | Admin |
+--------------------------------------+------+------------+---------------------------+-------+ +--------------------------------------+------+------------+---------------------------+-------+
| {$apiKey3} | - | +++ | - | Admin | | {$apiKey3->key} | - | +++ | - | Admin |
+--------------------------------------+------+------------+---------------------------+-------+ +--------------------------------------+------+------------+---------------------------+-------+
OUTPUT, OUTPUT,
@ -71,9 +71,9 @@ class ListKeysCommandTest extends TestCase
+--------------------------------------+------+-----------------+-------+ +--------------------------------------+------+-----------------+-------+
| Key | Name | Expiration date | Roles | | Key | Name | Expiration date | Roles |
+--------------------------------------+------+-----------------+-------+ +--------------------------------------+------+-----------------+-------+
| {$apiKey1} | - | - | Admin | | {$apiKey1->key} | - | - | Admin |
+--------------------------------------+------+-----------------+-------+ +--------------------------------------+------+-----------------+-------+
| {$apiKey2} | - | - | Admin | | {$apiKey2->key} | - | - | Admin |
+--------------------------------------+------+-----------------+-------+ +--------------------------------------+------+-----------------+-------+
OUTPUT, OUTPUT,
@ -97,18 +97,18 @@ class ListKeysCommandTest extends TestCase
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| Key | Name | Expiration date | Roles | | Key | Name | Expiration date | Roles |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| {$apiKey1} | - | - | Admin | | {$apiKey1->key} | - | - | Admin |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| {$apiKey2} | - | - | Author only | | {$apiKey2->key} | - | - | Author only |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| {$apiKey3} | - | - | Domain only: example.com | | {$apiKey3->key} | - | - | Domain only: example.com |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| {$apiKey4} | - | - | Admin | | {$apiKey4->key} | - | - | Admin |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| {$apiKey5} | - | - | Author only | | {$apiKey5->key} | - | - | Author only |
| | | | Domain only: example.com | | | | | Domain only: example.com |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
| {$apiKey6} | - | - | Admin | | {$apiKey6->key} | - | - | Admin |
+--------------------------------------+------+-----------------+--------------------------+ +--------------------------------------+------+-----------------+--------------------------+
OUTPUT, OUTPUT,
@ -125,13 +125,13 @@ class ListKeysCommandTest extends TestCase
+--------------------------------------+---------------+-----------------+-------+ +--------------------------------------+---------------+-----------------+-------+
| Key | Name | Expiration date | Roles | | Key | Name | Expiration date | Roles |
+--------------------------------------+---------------+-----------------+-------+ +--------------------------------------+---------------+-----------------+-------+
| {$apiKey1} | Alice | - | Admin | | {$apiKey1->key} | Alice | - | Admin |
+--------------------------------------+---------------+-----------------+-------+ +--------------------------------------+---------------+-----------------+-------+
| {$apiKey2} | Alice and Bob | - | Admin | | {$apiKey2->key} | Alice and Bob | - | Admin |
+--------------------------------------+---------------+-----------------+-------+ +--------------------------------------+---------------+-----------------+-------+
| {$apiKey3} | | - | Admin | | {$apiKey3->key} | | - | Admin |
+--------------------------------------+---------------+-----------------+-------+ +--------------------------------------+---------------+-----------------+-------+
| {$apiKey4} | - | - | Admin | | {$apiKey4->key} | - | - | Admin |
+--------------------------------------+---------------+-----------------+-------+ +--------------------------------------+---------------+-----------------+-------+
OUTPUT, OUTPUT,

View File

@ -140,7 +140,7 @@ class ListShortUrlsCommandTest extends TestCase
public static function provideOptionalFlags(): iterable public static function provideOptionalFlags(): iterable
{ {
$apiKey = ApiKey::fromMeta(ApiKeyMeta::fromParams(name: 'my api key')); $apiKey = ApiKey::fromMeta(ApiKeyMeta::fromParams(name: 'my api key'));
$key = $apiKey->toString(); $key = $apiKey->key;
yield 'tags only' => [ yield 'tags only' => [
['--show-tags' => true], ['--show-tags' => true],

View File

@ -7,16 +7,16 @@ namespace Shlinkio\Shlink\Rest\ApiKey\Model;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
final class ApiKeyMeta final readonly class ApiKeyMeta
{ {
/** /**
* @param iterable<RoleDefinition> $roleDefinitions * @param iterable<RoleDefinition> $roleDefinitions
*/ */
private function __construct( private function __construct(
public readonly string $key, public string $key,
public readonly string|null $name, public string|null $name,
public readonly Chronos|null $expirationDate, public Chronos|null $expirationDate,
public readonly iterable $roleDefinitions, public iterable $roleDefinitions,
) { ) {
} }

View File

@ -19,10 +19,9 @@ class ApiKey extends AbstractEntity
{ {
/** /**
* @param Collection<string, ApiKeyRole> $roles * @param Collection<string, ApiKeyRole> $roles
* @throws Exception
*/ */
private function __construct( private function __construct(
private string $key, public readonly string $key,
public readonly string|null $name = null, public readonly string|null $name = null,
public readonly Chronos|null $expirationDate = null, public readonly Chronos|null $expirationDate = null,
private bool $enabled = true, private bool $enabled = true,
@ -75,16 +74,6 @@ class ApiKey extends AbstractEntity
return $this->isEnabled() && ! $this->isExpired(); return $this->isEnabled() && ! $this->isExpired();
} }
public function __toString(): string
{
return $this->key;
}
public function toString(): string
{
return $this->key;
}
public function spec(string|null $context = null): Specification public function spec(string|null $context = null): Specification
{ {
$specs = $this->roles->map(fn (ApiKeyRole $role) => Role::toSpec($role, $context))->getValues(); $specs = $this->roles->map(fn (ApiKeyRole $role) => Role::toSpec($role, $context))->getValues();

View File

@ -8,7 +8,6 @@ use Cake\Chronos\Chronos;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use ReflectionObject;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Rest\ApiKey\Model\ApiKeyMeta; use Shlinkio\Shlink\Rest\ApiKey\Model\ApiKeyMeta;
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition; use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
@ -51,12 +50,7 @@ class ApiKeyFixture extends AbstractFixture implements DependentFixtureInterface
private function buildApiKey(string $key, bool $enabled, Chronos|null $expiresAt = null): ApiKey private function buildApiKey(string $key, bool $enabled, Chronos|null $expiresAt = null): ApiKey
{ {
$apiKey = ApiKey::fromMeta(ApiKeyMeta::fromParams(expirationDate: $expiresAt)); $apiKey = ApiKey::fromMeta(ApiKeyMeta::fromParams(key: $key, expirationDate: $expiresAt));
$ref = new ReflectionObject($apiKey);
$keyProp = $ref->getProperty('key');
$keyProp->setAccessible(true);
$keyProp->setValue($apiKey, $key);
if (! $enabled) { if (! $enabled) {
$apiKey->disable(); $apiKey->disable();
} }

View File

@ -130,18 +130,17 @@ class AuthenticationMiddlewareTest extends TestCase
public function validApiKeyFallsBackToNextMiddleware(): void public function validApiKeyFallsBackToNextMiddleware(): void
{ {
$apiKey = ApiKey::create(); $apiKey = ApiKey::create();
$key = $apiKey->toString();
$request = ServerRequestFactory::fromGlobals() $request = ServerRequestFactory::fromGlobals()
->withAttribute( ->withAttribute(
RouteResult::class, RouteResult::class,
RouteResult::fromRoute(new Route('bar', self::getDummyMiddleware()), []), RouteResult::fromRoute(new Route('bar', self::getDummyMiddleware()), []),
) )
->withHeader('X-Api-Key', $key); ->withHeader('X-Api-Key', $apiKey->key);
$this->handler->expects($this->once())->method('handle')->with( $this->handler->expects($this->once())->method('handle')->with(
$request->withAttribute(ApiKey::class, $apiKey), $request->withAttribute(ApiKey::class, $apiKey),
)->willReturn(new Response()); )->willReturn(new Response());
$this->apiKeyService->expects($this->once())->method('check')->with($key)->willReturn( $this->apiKeyService->expects($this->once())->method('check')->with($apiKey->key)->willReturn(
new ApiKeyCheckResult($apiKey), new ApiKeyCheckResult($apiKey),
); );