Created new env var to programatically provide an initial API key

This commit is contained in:
Alejandro Celaya
2022-09-11 10:45:03 +02:00
parent e6ee4ceae2
commit f5138385be
9 changed files with 119 additions and 10 deletions

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\ApiKey;
use Doctrine\ORM\EntityManager;
use Mezzio\Application;
use Psr\Container\ContainerInterface;
use Shlinkio\Shlink\Rest\ApiKey\Repository\ApiKeyRepositoryInterface;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class InitialApiKeyDelegator
{
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
{
$initialApiKey = $container->get('config')['initial_api_key'] ?? null;
if ($initialApiKey !== null) {
$this->createInitialApiKey($initialApiKey, $container);
}
return $callback();
}
private function createInitialApiKey(string $initialApiKey, ContainerInterface $container): void
{
/** @var ApiKeyRepositoryInterface $repo */
$repo = $container->get(EntityManager::class)->getRepository(ApiKey::class);
$repo->createInitialApiKey($initialApiKey);
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\ApiKey\Repository;
use Doctrine\DBAL\LockMode;
use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepository;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ApiKeyRepository extends EntitySpecificationRepository implements ApiKeyRepositoryInterface
{
public function createInitialApiKey(string $apiKey): void
{
$this->getEntityManager()->wrapInTransaction(function () use ($apiKey): void {
$qb = $this->getEntityManager()->createQueryBuilder();
$amountOfApiKeys = $qb->select('COUNT(a.id)')
->from(ApiKey::class, 'a')
->getQuery()
->setLockMode(LockMode::PESSIMISTIC_WRITE)
->getSingleScalarResult();
if ($amountOfApiKeys === 0) {
$this->getEntityManager()->persist(ApiKey::fromKey($apiKey));
$this->getEntityManager()->flush();
}
});
}
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\ApiKey\Repository;
use Doctrine\Persistence\ObjectRepository;
use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryInterface;
interface ApiKeyRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
{
/**
* Will create provided API key only if there's no API keys yet
*/
public function createInitialApiKey(string $apiKey): void;
}

View File

@@ -23,16 +23,14 @@ class ApiKey extends AbstractEntity
private bool $enabled;
/** @var Collection|ApiKeyRole[] */
private Collection $roles;
private ?string $name;
private ?string $name = null;
/**
* @throws Exception
*/
private function __construct(?string $name = null, ?Chronos $expirationDate = null)
private function __construct(?string $key = null)
{
$this->key = Uuid::uuid4()->toString();
$this->expirationDate = $expirationDate;
$this->name = $name;
$this->key = $key ?? Uuid::uuid4()->toString();
$this->enabled = true;
$this->roles = new ArrayCollection();
}
@@ -44,7 +42,10 @@ class ApiKey extends AbstractEntity
public static function fromMeta(ApiKeyMeta $meta): self
{
$apiKey = new self($meta->name, $meta->expirationDate);
$apiKey = self::create();
$apiKey->name = $meta->name;
$apiKey->expirationDate = $meta->expirationDate;
foreach ($meta->roleDefinitions as $roleDefinition) {
$apiKey->registerRole($roleDefinition);
}
@@ -52,6 +53,11 @@ class ApiKey extends AbstractEntity
return $apiKey;
}
public static function fromKey(string $key): self
{
return new self($key);
}
public function getExpirationDate(): ?Chronos
{
return $this->expirationDate;