Skip to content
This repository has been archived by the owner on May 3, 2023. It is now read-only.

Create a new ready session use case #10

Merged
merged 19 commits into from Apr 8, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions composer.json
Expand Up @@ -6,6 +6,7 @@
"php": "^7.2.5",
"ext-ctype": "*",
"ext-iconv": "*",
"ramsey/uuid": "^4.0",
"sensio/framework-extra-bundle": "^5.1",
"surfnet/stepup-saml-bundle": "^4.1",
"symfony/asset": "4.4.*",
Expand All @@ -16,6 +17,7 @@
"symfony/framework-bundle": "4.4.*",
"symfony/http-client": "4.4.*",
"symfony/intl": "4.4.*",
"symfony/messenger": "4.4.*",
"symfony/monolog-bundle": "^3.1",
"symfony/security-bundle": "4.4.*",
"symfony/serializer-pack": "*",
Expand All @@ -24,6 +26,7 @@
"symfony/yaml": "4.4.*"
},
"require-dev": {
"ext-json": "*",
"ibuildings/qa-pack": "^1.8",
"symfony/debug-pack": "*",
"symfony/maker-bundle": "^1.0",
Expand Down
1,889 changes: 1,445 additions & 444 deletions composer.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions config/packages/messenger.yaml
@@ -0,0 +1,7 @@
framework:
messenger:
# The bus that is going to be injected when injecting MessageBusInterface
default_bus: command.bus
buses:
command.bus: ~
query.bus: ~
4 changes: 4 additions & 0 deletions config/packages/parameters.yaml.dist
@@ -0,0 +1,4 @@
parameters:
app.authorization_token:
app.opaque_id:
app.readid_server_fqdn:
4 changes: 4 additions & 0 deletions config/packages/test/parameters.yaml
@@ -0,0 +1,4 @@
parameters:
app.authorization_token: 'authorization_token'
app.opaque_id: 'opaque_id'
app.readid_server_fqdn: 'readid.server.com'
20 changes: 20 additions & 0 deletions config/services.yaml
Expand Up @@ -25,3 +25,23 @@ services:

# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones

command_handlers:
namespace: StepupReadId\Application\
resource: '%kernel.project_dir%/src/Application/**/*CommandHandler.php'
autoconfigure: false
tags:
- { name: messenger.message_handler, bus: command.bus }

query_handlers:
namespace: StepupReadId\Application\
resource: '%kernel.project_dir%/src/Application/**/*QueryHandler.php'
autoconfigure: false
tags:
- { name: messenger.message_handler, bus: query.bus }

StepupReadId\Infrastructure\Services\HttpReadIDConfiguration:
arguments:
- '%app.authorization_token%'
- '%app.opaque_id%'
- '%app.readid_server_fqdn%'
3 changes: 3 additions & 0 deletions config/services_test.yaml
Expand Up @@ -7,3 +7,6 @@ services:
# aliases are prefixed with test. For example:
#
# test.App\Service\MyService: '@App\Service\MyService'

test.StepupReadId\Application\ReadySession\GetReadySessionQueryHandler: '@StepupReadId\Application\ReadySession\GetReadySessionQueryHandler'
test.Symfony\Contracts\HttpClient\HttpClientInterface: '@Symfony\Contracts\HttpClient\HttpClientInterface'
21 changes: 21 additions & 0 deletions src/Application/ReadySession/GetReadySessionQuery.php
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Application\ReadySession;

final class GetReadySessionQuery
{
/** @var int */
private $ttl;

public function __construct(int $ttl)
{
$this->ttl = $ttl;
}

public function ttl(): int
{
return $this->ttl;
}
}
27 changes: 27 additions & 0 deletions src/Application/ReadySession/GetReadySessionQueryHandler.php
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Application\ReadySession;

use StepupReadId\Domain\ReadySession\Model\ReadySession;
use StepupReadId\Domain\ReadySession\Model\ReadySessionTTL;
use StepupReadId\Domain\ReadySession\Services\RequestReadySessionInterface;

final class GetReadySessionQueryHandler
{
/** @var RequestReadySessionInterface */
private $requestReadySession;

public function __construct(RequestReadySessionInterface $requestReadySession)
{
$this->requestReadySession = $requestReadySession;
}

public function __invoke(GetReadySessionQuery $query): ReadySession
{
$ttl = ReadySessionTTL::fromInteger($query->ttl());

return $this->requestReadySession->with($ttl);
}
}
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Exception;

use InvalidArgumentException;

final class InvalidReadySessionBase64ImageException extends InvalidArgumentException
{
public static function becauseNoValidHeader(): self
{
return new self('Invalid base64 image header');
}
}
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Exception;

use InvalidArgumentException;
use StepupReadId\Domain\ReadySession\Model\ReadySessionTTL;
use function sprintf;

final class InvalidReadySessionTTLException extends InvalidArgumentException
{
public static function becauseOutOfRange(int $ttl): self
{
return new self(
sprintf(
'Invalid TTL (%d), must be between %d and %d',
$ttl,
ReadySessionTTL::MINIMUM_TTL,
ReadySessionTTL::MINIMUM_TTL
)
);
}
sgomez marked this conversation as resolved.
Show resolved Hide resolved
}
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Exception;

use InvalidArgumentException;

final class InvalidReadySessionTimestampException extends InvalidArgumentException
{
public static function becauseShouldBeGreaterThanZero(): self
{
return new self('Timestamp must be greater than zero.');
}
}
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Exception;

use RuntimeException;

final class RequestReadySessionAuthorizationException extends RuntimeException
{
}
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Exception;

use RuntimeException;

final class RequestReadySessionBadRequestException extends RuntimeException
{
}
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Exception;

use RuntimeException;
use function sprintf;

final class RequestReadySessionConnectionException extends RuntimeException
{
public static function becauseTransportError(string $cause): self
{
return new self(sprintf('Transport error: %s', $cause));
}

public static function becauseResponseIsInvalid(): self
{
return new self('Invalid response');
}
}
58 changes: 58 additions & 0 deletions src/Domain/ReadySession/Model/ReadySession.php
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Model;

final class ReadySession
sgomez marked this conversation as resolved.
Show resolved Hide resolved
{
/** @var ReadySessionId */
private $id;
/** @var ReadySessionBase64Image */
private $qrCode;
/** @var ReadySessionJwtToken */
private $jwtToken;
/** @var ReadySessionTimestamp */
private $timestamp;

private function __construct(
ReadySessionId $id,
ReadySessionBase64Image $qrCode,
ReadySessionJwtToken $jwtToken,
ReadySessionTimestamp $timestamp
) {
$this->id = $id;
$this->qrCode = $qrCode;
$this->jwtToken = $jwtToken;
$this->timestamp = $timestamp;
}

public static function create(
ReadySessionId $id,
ReadySessionBase64Image $qrCode,
ReadySessionJwtToken $jwtToken,
ReadySessionTimestamp $timestamp
): ReadySession {
return new self($id, $qrCode, $jwtToken, $timestamp);
}

public function id(): ReadySessionId
{
return $this->id;
}

public function qrCode(): ReadySessionBase64Image
{
return $this->qrCode;
}

public function jwtToken(): ReadySessionJwtToken
{
return $this->jwtToken;
}

public function timestamp(): ReadySessionTimestamp
{
return $this->timestamp;
}
}
43 changes: 43 additions & 0 deletions src/Domain/ReadySession/Model/ReadySessionBase64Image.php
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Model;

use StepupReadId\Domain\ReadySession\Exception\InvalidReadySessionBase64ImageException;
use function preg_match;

final class ReadySessionBase64Image
MKodde marked this conversation as resolved.
Show resolved Hide resolved
{
/** @var string */
private $value;

public function __construct(string $base64Image)
{
$this->checkValidBase64Image($base64Image);

$this->value = $base64Image;
sgomez marked this conversation as resolved.
Show resolved Hide resolved
}

public static function fromString(string $base64Image): ReadySessionBase64Image
{
return new self($base64Image);
}

public function value(): string
{
return $this->value;
}

public function equals(ReadySessionBase64Image $other): bool
{
return $this->value === $other->value;
}

private function checkValidBase64Image(string $base64Image): void
{
if (!preg_match('/^data:image\/[^;]+;base64,/', $base64Image)) {
throw InvalidReadySessionBase64ImageException::becauseNoValidHeader();
}
}
}
34 changes: 34 additions & 0 deletions src/Domain/ReadySession/Model/ReadySessionId.php
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Model;

use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
MKodde marked this conversation as resolved.
Show resolved Hide resolved

final class ReadySessionId
{
/** @var UuidInterface */
private $value;

private function __construct(UuidInterface $readySessionId)
{
$this->value = $readySessionId;
}

public static function fromString(string $readySessionId): ReadySessionId
{
return new self(Uuid::fromString($readySessionId));
}

public function value(): string
{
return $this->value->toString();
}

public function equals(ReadySessionId $other): bool
{
return $this->value->equals($other);
}
}
31 changes: 31 additions & 0 deletions src/Domain/ReadySession/Model/ReadySessionJwtToken.php
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace StepupReadId\Domain\ReadySession\Model;

final class ReadySessionJwtToken
{
/** @var string */
private $value;

private function __construct(string $jwtToken)
{
$this->value = $jwtToken;
}

public static function fromString(string $jwtToken): self
{
return new self($jwtToken);
}

public function value(): string
{
return $this->value;
}

public function equals(ReadySessionJwtToken $other): bool
{
return $this->value === $other->value;
}
}