From 83635f2d6a3313694e35ecc70a6a3b44e379263a Mon Sep 17 00:00:00 2001 From: Rodion Liuborets Date: Tue, 7 Feb 2023 22:57:32 +0200 Subject: [PATCH 01/19] Master -> Development (#315) * Release 4.1.0 * Add helper method to GetSessionResult getFaceComparisonChecks * Add several fixes, update php8.0 -> 8.1, guzzlehttp/guzzle -> 7.0, guzzlehttp/psr7 -> 2.4 * Update github actions php8.0 -> 8.1 * Update github actions for sonar check php8.0 -> 8.1 * Remove support of php7.1 * Modify sonar config for php8.1 * Add php7.4, php8.0 support * Add php7.4, php8.0 support * Update README.md (#306) * Updated dependencies * Fixed psr/log for php7.4 * Improve identity report view * Fix version to 4.2.0 (#314) --- composer.json | 4 +- .../resources/views/partial/report.blade.php | 41 +++++++++++++++---- src/Constants.php | 2 +- .../Session/Create/SdkConfigBuilder.php | 2 +- .../IdentityProfilePreviewResponse.php | 4 ++ src/Util/Logger.php | 2 +- 6 files changed, 43 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index ff6ed4c0..602c2179 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "yoti/yoti-php-sdk", "description": "Yoti SDK for quickly integrating your PHP backend with Yoti", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "yoti", "sdk" @@ -32,7 +32,7 @@ "phpstan/phpstan-strict-rules": "^0.12.1", "phpstan/extension-installer": "^1.0", "psr/log": "^1.1", - "symfony/phpunit-bridge": "^5.1" + "symfony/phpunit-bridge": "^6.2" }, "autoload-dev": { "psr-4": { diff --git a/examples/profile/resources/views/partial/report.blade.php b/examples/profile/resources/views/partial/report.blade.php index 26d8f3bb..28bdd3f0 100644 --- a/examples/profile/resources/views/partial/report.blade.php +++ b/examples/profile/resources/views/partial/report.blade.php @@ -1,12 +1,39 @@ - - @foreach ($report as $key => $value) +@foreach ($report as $key => $value) +
+ - + + + @foreach ($value as $name => $result) + @if (is_array($result)) + @foreach ($result as $data => $view) + @if (is_array($view)) + @foreach ($view as $key2 => $value2) + @if (is_array($value2)) + {{json_encode($value2)}} + @else + + + + @endif + @endforeach + @else + + + + @endif + @endforeach + @else + + + + @endif + @endforeach + + +
{{ $key }} -
-                    {{ $value }}
-                
+

{{ $key }}

{{ $key2 }}
{{ $value2 }}
{{ $data }}
{{ $view }}
{{ $name }}
{{ $result }}
@endforeach - \ No newline at end of file diff --git a/src/Constants.php b/src/Constants.php index 6933f0d9..f784e2ec 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -25,7 +25,7 @@ class Constants public const SDK_IDENTIFIER = 'PHP'; /** Default SDK version */ - public const SDK_VERSION = '4.1.0'; + public const SDK_VERSION = '4.2.0'; /** Base url for connect page (user will be redirected to this page eg. baseurl/app-id) */ public const CONNECT_BASE_URL = 'https://www.yoti.com/connect'; diff --git a/src/DocScan/Session/Create/SdkConfigBuilder.php b/src/DocScan/Session/Create/SdkConfigBuilder.php index 01bd1d1b..c91adc05 100644 --- a/src/DocScan/Session/Create/SdkConfigBuilder.php +++ b/src/DocScan/Session/Create/SdkConfigBuilder.php @@ -172,7 +172,7 @@ public function withIdDocumentTextExtractionReclassificationRetries(int $reclass /** * @deprecated from 4.2.0, @see withIdDocumentTextExtractionGenericAttempts */ - public function withIdDocumentTextExtractionGenericRetries(int $genericRetries) + public function withIdDocumentTextExtractionGenericRetries(int $genericRetries): void { } diff --git a/src/DocScan/Session/Retrieve/IdentityProfilePreviewResponse.php b/src/DocScan/Session/Retrieve/IdentityProfilePreviewResponse.php index 7ee8c7fa..6a3958eb 100644 --- a/src/DocScan/Session/Retrieve/IdentityProfilePreviewResponse.php +++ b/src/DocScan/Session/Retrieve/IdentityProfilePreviewResponse.php @@ -6,6 +6,10 @@ class IdentityProfilePreviewResponse { private ?MediaResponse $media = null; + /** + * @param array $sessionData + * @throws \Yoti\Exception\DateTimeException + */ public function __construct(array $sessionData) { if (isset($sessionData['media'])) { diff --git a/src/Util/Logger.php b/src/Util/Logger.php index 4a69fc01..c9fdc7e8 100644 --- a/src/Util/Logger.php +++ b/src/Util/Logger.php @@ -27,7 +27,7 @@ class Logger extends AbstractLogger /** * @inheritDoc */ - public function log($level, $message, array $context = []) + public function log($level, $message, array $context = []): void { if (!in_array($level, self::LEVELS, true)) { throw new InvalidArgumentException(sprintf('"%s" level is not allowed', $level)); From 636648316a96452dac121021aaddf08113976925 Mon Sep 17 00:00:00 2001 From: Rodion Liuborets Date: Tue, 14 Feb 2023 13:11:33 +0200 Subject: [PATCH 02/19] SDK-2225 Import token support (#317) --- src/DocScan/Session/Create/ImportToken.php | 51 ++++++++ .../Session/Create/ImportTokenBuilder.php | 27 ++++ .../Session/Create/SessionSpecification.php | 26 +++- .../Create/SessionSpecificationBuilder.php | 22 +++- .../Session/Retrieve/GetSessionResult.php | 11 ++ .../Session/Retrieve/ImportTokenResponse.php | 43 +++++++ .../Session/Create/ImportTokenBuilderTest.php | 117 ++++++++++++++++++ .../SessionSpecificationBuilderTest.php | 48 +++++++ .../Session/Retrieve/GetSessionResultTest.php | 28 +++++ .../Retrieve/ImportTokenResponseTest.php | 38 ++++++ 10 files changed, 403 insertions(+), 8 deletions(-) create mode 100644 src/DocScan/Session/Create/ImportToken.php create mode 100644 src/DocScan/Session/Create/ImportTokenBuilder.php create mode 100644 src/DocScan/Session/Retrieve/ImportTokenResponse.php create mode 100644 tests/DocScan/Session/Create/ImportTokenBuilderTest.php create mode 100644 tests/DocScan/Session/Retrieve/ImportTokenResponseTest.php diff --git a/src/DocScan/Session/Create/ImportToken.php b/src/DocScan/Session/Create/ImportToken.php new file mode 100644 index 00000000..4b2964e2 --- /dev/null +++ b/src/DocScan/Session/Create/ImportToken.php @@ -0,0 +1,51 @@ +validate($ttl); + $this->ttl = $ttl; + } + + public function jsonSerialize(): \stdClass + { + return (object)Json::withoutNullValues([ + 'ttl' => $this->getTtl(), + ]); + } + + /** + * @return int + */ + public function getTtl(): int + { + return $this->ttl; + } + + /** + * @throws DocScanException + */ + private function validate(int $ttl): void + { + if (self::MAX_TTL < $ttl || self::MIN_TTL > $ttl) { + throw new DocScanException( + 'Your TTL is invalid. Min value - ' . self::MIN_TTL . '.Max value - ' . self::MAX_TTL . '.' + ); + } + } +} diff --git a/src/DocScan/Session/Create/ImportTokenBuilder.php b/src/DocScan/Session/Create/ImportTokenBuilder.php new file mode 100644 index 00000000..84340213 --- /dev/null +++ b/src/DocScan/Session/Create/ImportTokenBuilder.php @@ -0,0 +1,27 @@ +ttl = $ttl ?? self::DEFAULT_TTL; + + return $this; + } + + /** + * @throws DocScanException + */ + public function build(): ImportToken + { + return new ImportToken($this->ttl); + } +} diff --git a/src/DocScan/Session/Create/SessionSpecification.php b/src/DocScan/Session/Create/SessionSpecification.php index ed9026aa..46ab1f4a 100644 --- a/src/DocScan/Session/Create/SessionSpecification.php +++ b/src/DocScan/Session/Create/SessionSpecification.php @@ -80,6 +80,11 @@ class SessionSpecification implements JsonSerializable private ?bool $createIdentityProfilePreview; + /** + * @var ImportToken|null + */ + private $importToken; + /** * @param int|null $clientSessionTokenTtl * @param string|null $sessionDeadline @@ -94,7 +99,8 @@ class SessionSpecification implements JsonSerializable * @param IbvOptions|null $ibvOptions * @param object|null $subject * @param object|null $identityProfileRequirements - * @param bool $createIdentityProfilePreview + * @param bool|null $createIdentityProfilePreview + * @param ImportToken|null $importToken */ public function __construct( ?int $clientSessionTokenTtl, @@ -108,9 +114,10 @@ public function __construct( array $requiredDocuments = [], ?bool $blockBiometricConsent = null, ?IbvOptions $ibvOptions = null, - $subject = null, - $identityProfileRequirements = null, - ?bool $createIdentityProfilePreview = null + ?object $subject = null, + ?object $identityProfileRequirements = null, + ?bool $createIdentityProfilePreview = null, + ?ImportToken $importToken = null ) { $this->clientSessionTokenTtl = $clientSessionTokenTtl; $this->sessionDeadline = $sessionDeadline; @@ -126,6 +133,7 @@ public function __construct( $this->subject = $subject; $this->identityProfileRequirements = $identityProfileRequirements; $this->createIdentityProfilePreview = $createIdentityProfilePreview; + $this->importToken = $importToken; } /** @@ -148,6 +156,7 @@ public function jsonSerialize(): stdClass 'subject' => $this->getSubject(), 'identity_profile_requirements' => $this->getIdentityProfileRequirements(), 'create_identity_profile_preview' => $this->getCreateIdentityProfilePreview(), + 'import_token' => $this->getImportToken(), ]); } @@ -247,7 +256,7 @@ public function getIbvOptions(): ?IbvOptions /** * @return object|null */ - public function getSubject() + public function getSubject(): ?object { return $this->subject; } @@ -255,7 +264,7 @@ public function getSubject() /** * @return object|null */ - public function getIdentityProfileRequirements() + public function getIdentityProfileRequirements(): ?object { return $this->identityProfileRequirements; } @@ -264,4 +273,9 @@ public function getCreateIdentityProfilePreview(): ?bool { return $this->createIdentityProfilePreview; } + + public function getImportToken(): ?ImportToken + { + return $this->importToken; + } } diff --git a/src/DocScan/Session/Create/SessionSpecificationBuilder.php b/src/DocScan/Session/Create/SessionSpecificationBuilder.php index cf39a8c0..bb54de9e 100644 --- a/src/DocScan/Session/Create/SessionSpecificationBuilder.php +++ b/src/DocScan/Session/Create/SessionSpecificationBuilder.php @@ -4,6 +4,7 @@ namespace Yoti\DocScan\Session\Create; +use DateTimeImmutable; use Yoti\DocScan\Session\Create\Check\RequestedCheck; use Yoti\DocScan\Session\Create\Filters\RequiredDocument; use Yoti\DocScan\Session\Create\Task\RequestedTask; @@ -77,6 +78,11 @@ class SessionSpecificationBuilder */ private $identityProfileRequirements; + /** + * @var ImportToken|null + */ + private $importToken; + /** * @var bool */ @@ -93,10 +99,10 @@ public function withClientSessionTokenTtl(int $clientSessionTokenTtl): self } /** - * @param \DateTimeImmutable $sessionDeadline + * @param DateTimeImmutable $sessionDeadline * @return $this */ - public function withSessionDeadLine(\DateTimeImmutable $sessionDeadline): self + public function withSessionDeadLine(DateTimeImmutable $sessionDeadline): self { $this->sessionDeadline = $sessionDeadline->format(self::DATETIME_FORMAT); return $this; @@ -257,6 +263,17 @@ public function withCreateIdentityProfilePreview(): self return $this; } + /** + * @param ImportToken $importToken + * + * @return $this + */ + public function withImportToken($importToken): self + { + $this->importToken = $importToken; + return $this; + } + /** * @return SessionSpecification */ @@ -277,6 +294,7 @@ public function build(): SessionSpecification $this->subject, $this->identityProfileRequirements, $this->createIdentityProfilePreview, + $this->importToken, ); } } diff --git a/src/DocScan/Session/Retrieve/GetSessionResult.php b/src/DocScan/Session/Retrieve/GetSessionResult.php index c197f23c..919053c3 100644 --- a/src/DocScan/Session/Retrieve/GetSessionResult.php +++ b/src/DocScan/Session/Retrieve/GetSessionResult.php @@ -53,6 +53,8 @@ class GetSessionResult private ?IdentityProfilePreviewResponse $identityProfilePreview; + private ?ImportTokenResponse $importToken; + /** * DocScanSession constructor. * @param array $sessionData @@ -90,6 +92,10 @@ public function __construct(array $sessionData) $sessionData['identity_profile_preview'] ); } + + if (isset($sessionData['import_token'])) { + $this->importToken = new ImportTokenResponse($sessionData['import_token']); + } } /** @@ -314,4 +320,9 @@ public function getIdentityProfilePreview(): ?IdentityProfilePreviewResponse { return $this->identityProfilePreview; } + + public function getImportToken(): ?ImportTokenResponse + { + return $this->importToken; + } } diff --git a/src/DocScan/Session/Retrieve/ImportTokenResponse.php b/src/DocScan/Session/Retrieve/ImportTokenResponse.php new file mode 100644 index 00000000..169642be --- /dev/null +++ b/src/DocScan/Session/Retrieve/ImportTokenResponse.php @@ -0,0 +1,43 @@ + $data + * + * @throws DateTimeException + */ + public function __construct(array $data) + { + if (isset($data['media'])) { + $this->media = new MediaResponse($data['media']); + } + if (isset($data['failure_reason'])) { + $this->failureReason = $data['failure_reason']; + } + } + + /** + * @return string|null + */ + public function getFailureReason(): ?string + { + return $this->failureReason; + } + + /** + * @return MediaResponse|null + */ + public function getMedia(): ?MediaResponse + { + return $this->media; + } +} diff --git a/tests/DocScan/Session/Create/ImportTokenBuilderTest.php b/tests/DocScan/Session/Create/ImportTokenBuilderTest.php new file mode 100644 index 00000000..acb2b2da --- /dev/null +++ b/tests/DocScan/Session/Create/ImportTokenBuilderTest.php @@ -0,0 +1,117 @@ +withTtl() + ->build(); + + $this->assertEquals(self::DEFAULT_TTL, $result->getTtl()); + $this->assertIsInt($result->getTtl()); + } + + /** + * @test + * @covers ::build + * @covers ::withTtl + * @covers \Yoti\DocScan\Session\Create\ImportToken::__construct + * @covers \Yoti\DocScan\Session\Create\ImportToken::getTtl + */ + public function builderWithTtlShouldSetCorrectTtl() + { + $ttl = 3600 * 24 * 60; + + $result = (new ImportTokenBuilder()) + ->withTtl($ttl) + ->build(); + + $this->assertEquals($ttl, $result->getTtl()); + } + + /** + * @test + * @covers \Yoti\DocScan\Session\Create\ImportToken::jsonSerialize + */ + public function shouldSerializeWithCorrectProperties(): void + { + $ttl = 3600 * 24 * 60; + + $result = (new ImportTokenBuilder()) + ->withTtl($ttl) + ->build(); + + $expected = [ + 'ttl' => $ttl, + ]; + + $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); + } + + /** + * @test + * @covers ::build + * @covers ::withTtl + * @covers \Yoti\DocScan\Session\Create\ImportToken::__construct + * @covers \Yoti\DocScan\Session\Create\ImportToken::validate + * @covers \Yoti\DocScan\Session\Create\ImportToken::getTtl + */ + public function builderWithIncorrectSmallTtlShouldThrowException() + { + $this->expectException(DocScanException::class); + $this->expectExceptionMessage( + 'Your TTL is invalid. Min value - ' . self::MIN_TTL . '.Max value - ' . self::MAX_TTL . '.' + ); + + $ttl = 3600 * 24 * 29; + + $result = (new ImportTokenBuilder()) + ->withTtl($ttl) + ->build(); + } + + /** + * @test + * @covers ::build + * @covers ::withTtl + * @covers \Yoti\DocScan\Session\Create\ImportToken::__construct + * @covers \Yoti\DocScan\Session\Create\ImportToken::validate + * @covers \Yoti\DocScan\Session\Create\ImportToken::getTtl + */ + public function builderWithIncorrectBigTtlShouldThrowException() + { + $this->expectException(DocScanException::class); + $this->expectExceptionMessage( + 'Your TTL is invalid. Min value - ' . self::MIN_TTL . '.Max value - ' . self::MAX_TTL . '.' + ); + + $ttl = 3600 * 24 * 370; + + $result = (new ImportTokenBuilder()) + ->withTtl($ttl) + ->build(); + } +} diff --git a/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php b/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php index bbfac77d..3f3640b7 100644 --- a/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php +++ b/tests/DocScan/Session/Create/SessionSpecificationBuilderTest.php @@ -7,6 +7,7 @@ use Yoti\DocScan\Session\Create\Check\RequestedCheck; use Yoti\DocScan\Session\Create\Filters\RequiredDocument; use Yoti\DocScan\Session\Create\IbvOptions; +use Yoti\DocScan\Session\Create\ImportToken; use Yoti\DocScan\Session\Create\NotificationConfig; use Yoti\DocScan\Session\Create\SdkConfig; use Yoti\DocScan\Session\Create\SessionSpecificationBuilder; @@ -62,6 +63,11 @@ class SessionSpecificationBuilderTest extends TestCase */ private $identityProfileRequirements; + /** + * @var ImportToken + */ + private $importTokenMock; + public function setup(): void { $this->sdkConfigMock = $this->createMock(SdkConfig::class); @@ -81,6 +87,8 @@ public function setup(): void $this->ibvOptionsMock = $this->createMock(IbvOptions::class); + $this->importTokenMock = $this->createMock(ImportToken::class); + $this->subject = (object)[1 => 'some']; $this->identityProfileRequirements = (object)[ @@ -484,4 +492,44 @@ public function shouldReturnCorrectJsonStringWithIdentityProfilePreviewTrue() json_encode($sessionSpecification) ); } + + /** + * @test + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::getImportToken + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::__construct + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::withImportToken + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::build + */ + public function withImportTokenShouldSetImportToken() + { + $sessionSpecificationResult = (new SessionSpecificationBuilder()) + ->withImportToken($this->importTokenMock) + ->build(); + + $this->assertEquals($this->importTokenMock, $sessionSpecificationResult->getImportToken()); + } + + /** + * @test + * @covers \Yoti\DocScan\Session\Create\SessionSpecification::jsonSerialize + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::withImportToken + * @covers \Yoti\DocScan\Session\Create\SessionSpecificationBuilder::build + */ + public function shouldReturnCorrectJsonStringWithImportToken() + { + $sessionSpecification = (new SessionSpecificationBuilder()) + ->withImportToken($this->importTokenMock) + ->build(); + + $this->assertJsonStringEqualsJsonString( + json_encode([ + 'requested_checks' => [], + 'requested_tasks' => [], + 'required_documents' => [], + 'create_identity_profile_preview' => false, + 'import_token' => $this->importTokenMock, + ]), + json_encode($sessionSpecification) + ); + } } diff --git a/tests/DocScan/Session/Retrieve/GetSessionResultTest.php b/tests/DocScan/Session/Retrieve/GetSessionResultTest.php index 908e524c..705e82fb 100644 --- a/tests/DocScan/Session/Retrieve/GetSessionResultTest.php +++ b/tests/DocScan/Session/Retrieve/GetSessionResultTest.php @@ -9,6 +9,8 @@ use Yoti\DocScan\Session\Retrieve\GetSessionResult; use Yoti\DocScan\Session\Retrieve\IdentityProfilePreviewResponse; use Yoti\DocScan\Session\Retrieve\IdentityProfileResponse; +use Yoti\DocScan\Session\Retrieve\ImportTokenResponse; +use Yoti\DocScan\Session\Retrieve\MediaResponse; use Yoti\DocScan\Session\Retrieve\ThirdPartyIdentityFraudOneCheckResponse; use Yoti\Test\TestCase; use Yoti\Util\DateTime; @@ -258,4 +260,30 @@ public function shouldParseIdentityProfilePreviewResponse() $this->assertInstanceOf(IdentityProfilePreviewResponse::class, $result->getIdentityProfilePreview()); } + + /** + * @test + * @covers ::getImportToken + * @covers ::__construct + */ + public function shouldParseImportTokenResponse() + { + $input = [ + 'import_token' => [ + 'media' => [ + 'id' => 'SOME_ID', + 'type' => 'JSON', + 'created' => '2021-06-11T11:39:24Z', + 'last_updated' => '2021-06-11T11:39:24Z', + ], + 'failure_reason' => 'SOME_REASON' + ], + ]; + + $result = new GetSessionResult($input); + + $this->assertInstanceOf(ImportTokenResponse::class, $result->getImportToken()); + $this->assertInstanceOf(MediaResponse::class, $result->getImportToken()->getMedia()); + $this->assertEquals('SOME_REASON', $result->getImportToken()->getFailureReason()); + } } diff --git a/tests/DocScan/Session/Retrieve/ImportTokenResponseTest.php b/tests/DocScan/Session/Retrieve/ImportTokenResponseTest.php new file mode 100644 index 00000000..609a1591 --- /dev/null +++ b/tests/DocScan/Session/Retrieve/ImportTokenResponseTest.php @@ -0,0 +1,38 @@ + [ + 'id' => 'SOME_ID', + 'type' => 'JSON', + 'created' => '2021-06-11T11:39:24Z', + 'last_updated' => '2021-06-11T11:39:24Z', + ], + 'failure_reason' => 'SOME_REASON' + ]; + + $result = new ImportTokenResponse($data); + + $this->assertInstanceOf(MediaResponse::class, $result->getMedia()); + $this->assertInstanceOf(ImportTokenResponse::class, $result); + $this->assertEquals('SOME_REASON', $result->getFailureReason()); + } +} From 6e28b4ccf143b04cdd06ce17cea5f095e03e4c57 Mon Sep 17 00:00:00 2001 From: Rodion Liuborets Date: Thu, 16 Mar 2023 15:28:30 +0200 Subject: [PATCH 03/19] SDK-2241 Share V2 Create Session (#319) * SDK-2241 Share V2 Create Session * SDK-2250 Create Qr Code (#320) * SDK-2250 Create Qr Code * SDK-2258 Retrieve QR code (#321) * SDK-2258 Retrieve QR code * SDK-2244 Retrieve Session (#322) --- .../Http/Controllers/IdentityController.php | 64 ++ .../resources/views/identity.blade.php | 62 ++ src/Exception/IdentityException.php | 9 + src/Identity/Constraint/Constraint.php | 8 + src/Identity/Constraint/PreferredSources.php | 54 ++ src/Identity/Constraint/SourceConstraint.php | 43 ++ .../Constraint/SourceConstraintBuilder.php | 46 ++ .../Extension/BasicExtensionBuilder.php | 40 ++ src/Identity/Extension/Extension.php | 38 ++ .../Extension/ExtensionBuilderInterface.php | 8 + .../Extension/LocationConstraintContent.php | 61 ++ .../LocationConstraintExtensionBuilder.php | 82 +++ .../Extension/ThirdPartyAttributeContent.php | 38 ++ .../ThirdPartyAttributeExtensionBuilder.php | 66 ++ .../TransactionalFlowExtensionBuilder.php | 35 + src/Identity/IdentityService.php | 109 +++ src/Identity/Policy/Policy.php | 75 ++ src/Identity/Policy/PolicyBuilder.php | 332 +++++++++ src/Identity/Policy/WantedAnchor.php | 29 + src/Identity/Policy/WantedAnchorBuilder.php | 32 + src/Identity/Policy/WantedAttribute.php | 123 ++++ .../Policy/WantedAttributeBuilder.php | 77 +++ src/Identity/ShareSessionCreated.php | 71 ++ src/Identity/ShareSessionCreatedQrCode.php | 48 ++ src/Identity/ShareSessionFetched.php | 117 ++++ src/Identity/ShareSessionFetchedQrCode.php | 110 +++ src/Identity/ShareSessionNotification.php | 70 ++ .../ShareSessionNotificationBuilder.php | 65 ++ src/Identity/ShareSessionRequest.php | 110 +++ src/Identity/ShareSessionRequestBuilder.php | 84 +++ src/Util/Validation.php | 2 +- src/YotiClient.php | 69 +- .../Constraint/PreferredSourcesTest.php | 42 ++ .../SourceConstraintsBuilderTest.php | 66 ++ .../Extension/BasicExtensionBuilderTest.php | 40 ++ .../LocationConstraintContentTest.php | 44 ++ ...LocationConstraintExtensionBuilderTest.php | 164 +++++ .../ThirdPartyAttributeContentTest.php | 42 ++ ...hirdPartyAttributeExtensionBuilderTest.php | 132 ++++ .../TransactionalFlowExtensionBuilderTest.php | 36 + tests/Identity/IdentityServiceTest.php | 133 ++++ tests/Identity/Policy/PolicyBuilderTest.php | 644 ++++++++++++++++++ .../Policy/WantedAnchorBuilderTest.php | 39 ++ .../Policy/WantedAttributeBuilderTest.php | 162 +++++ .../ShareSessionCreatedQrCodeTest.php | 42 ++ tests/Identity/ShareSessionCreatedTest.php | 45 ++ .../ShareSessionFetchedQrCodeTest.php | 76 +++ tests/Identity/ShareSessionFetchedTest.php | 66 ++ .../ShareSessionNotificationBuilderTest.php | 80 +++ .../ShareSessionRequestBuilderTest.php | 100 +++ tests/YotiClientTest.php | 140 ++++ 51 files changed, 4257 insertions(+), 13 deletions(-) create mode 100644 examples/profile/app/Http/Controllers/IdentityController.php create mode 100644 examples/profile/resources/views/identity.blade.php create mode 100644 src/Exception/IdentityException.php create mode 100644 src/Identity/Constraint/Constraint.php create mode 100644 src/Identity/Constraint/PreferredSources.php create mode 100644 src/Identity/Constraint/SourceConstraint.php create mode 100644 src/Identity/Constraint/SourceConstraintBuilder.php create mode 100644 src/Identity/Extension/BasicExtensionBuilder.php create mode 100644 src/Identity/Extension/Extension.php create mode 100644 src/Identity/Extension/ExtensionBuilderInterface.php create mode 100644 src/Identity/Extension/LocationConstraintContent.php create mode 100644 src/Identity/Extension/LocationConstraintExtensionBuilder.php create mode 100644 src/Identity/Extension/ThirdPartyAttributeContent.php create mode 100644 src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php create mode 100644 src/Identity/Extension/TransactionalFlowExtensionBuilder.php create mode 100644 src/Identity/IdentityService.php create mode 100644 src/Identity/Policy/Policy.php create mode 100644 src/Identity/Policy/PolicyBuilder.php create mode 100644 src/Identity/Policy/WantedAnchor.php create mode 100644 src/Identity/Policy/WantedAnchorBuilder.php create mode 100644 src/Identity/Policy/WantedAttribute.php create mode 100644 src/Identity/Policy/WantedAttributeBuilder.php create mode 100644 src/Identity/ShareSessionCreated.php create mode 100644 src/Identity/ShareSessionCreatedQrCode.php create mode 100644 src/Identity/ShareSessionFetched.php create mode 100644 src/Identity/ShareSessionFetchedQrCode.php create mode 100644 src/Identity/ShareSessionNotification.php create mode 100644 src/Identity/ShareSessionNotificationBuilder.php create mode 100644 src/Identity/ShareSessionRequest.php create mode 100644 src/Identity/ShareSessionRequestBuilder.php create mode 100644 tests/Identity/Constraint/PreferredSourcesTest.php create mode 100644 tests/Identity/Constraint/SourceConstraintsBuilderTest.php create mode 100644 tests/Identity/Extension/BasicExtensionBuilderTest.php create mode 100644 tests/Identity/Extension/LocationConstraintContentTest.php create mode 100644 tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php create mode 100644 tests/Identity/Extension/ThirdPartyAttributeContentTest.php create mode 100644 tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php create mode 100644 tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php create mode 100644 tests/Identity/IdentityServiceTest.php create mode 100644 tests/Identity/Policy/PolicyBuilderTest.php create mode 100644 tests/Identity/Policy/WantedAnchorBuilderTest.php create mode 100644 tests/Identity/Policy/WantedAttributeBuilderTest.php create mode 100644 tests/Identity/ShareSessionCreatedQrCodeTest.php create mode 100644 tests/Identity/ShareSessionCreatedTest.php create mode 100644 tests/Identity/ShareSessionFetchedQrCodeTest.php create mode 100644 tests/Identity/ShareSessionFetchedTest.php create mode 100644 tests/Identity/ShareSessionNotificationBuilderTest.php create mode 100644 tests/Identity/ShareSessionRequestBuilderTest.php diff --git a/examples/profile/app/Http/Controllers/IdentityController.php b/examples/profile/app/Http/Controllers/IdentityController.php new file mode 100644 index 00000000..61b6317b --- /dev/null +++ b/examples/profile/app/Http/Controllers/IdentityController.php @@ -0,0 +1,64 @@ +build(); + + $redirectUri = 'https://host/redirect/'; + + $shareSessionRequest = (new ShareSessionRequestBuilder()) + ->withPolicy($policy) + ->withRedirectUri($redirectUri) + ->build(); + + $session = $client->createShareSession($shareSessionRequest); + + $createdQrCode = $client->createShareQrCode($session->getId()); + + $fetchedQrCode = $client->fetchShareQrCode($createdQrCode->getId()); + + $sessionFetched = $client->fetchShareSession($session->getId()); + + return view('identity', [ + 'title' => 'Digital Identity Complete Example', + // Creating session + 'sessionId' => $session->getId(), + 'sessionStatus' => $session->getStatus(), + 'sessionExpiry' => $session->getExpiry(), + // Creating QR code + 'createdQrCodeId' => $createdQrCode->getId(), + 'createdQrCodeUri' => $createdQrCode->getUri(), + // Fetch QR code + 'fetchedQrCodeExpiry' => $fetchedQrCode->getExpiry(), + 'fetchedQrCodeExtensions' => $fetchedQrCode->getExtensions(), + 'fetchedQrCodeRedirectUri' => $fetchedQrCode->getRedirectUri(), + 'fetchedQrCodeSessionId' => $fetchedQrCode->getSession()->getId(), + 'fetchedQrCodeSessionStatus' => $fetchedQrCode->getSession()->getStatus(), + 'fetchedQrCodeSessionExpiry' => $fetchedQrCode->getSession()->getExpiry(), + // Fetch session + 'fetchedSessionId' => $sessionFetched->getId(), + 'fetchedSessionStatus' => $sessionFetched->getStatus(), + 'fetchedSessionExpiry' => $sessionFetched->getExpiry(), + 'fetchedSessionCreated' => $sessionFetched->getCreated(), + 'fetchedSessionUpdated' => $sessionFetched->getUpdated(), + 'fetchedSessionQrCodeId' => $sessionFetched->getQrCodeId(), + 'fetchedSessionReceiptId' => $sessionFetched->getReceiptId(), + ]); + } catch (\Throwable $e) { + Log::error($e->getTraceAsString()); + throw new BadRequestHttpException($e->getMessage()); + } + } +} diff --git a/examples/profile/resources/views/identity.blade.php b/examples/profile/resources/views/identity.blade.php new file mode 100644 index 00000000..f4523ea3 --- /dev/null +++ b/examples/profile/resources/views/identity.blade.php @@ -0,0 +1,62 @@ + + + + + + + {{ $title }} + + + + + +
+
+
+ + Yoti + +
+ +

Digital Identity Share Complete Example page

+ +
+

Created Session

+

Id: {{$sessionId}}

+

Status: {{$sessionStatus}}

+

Expiry: {{$sessionExpiry}}

+
+ +
+

Created Session QR Code

+

Id: {{$createdQrCodeId}}

+

URI: {{$createdQrCodeUri}}

+
+ +
+

Fetched Session QR Code

+

Expiry: {{$fetchedQrCodeExpiry}}

+

Extensions: {{$fetchedQrCodeExtensions}}

+

Redirect URI: {{$fetchedQrCodeRedirectUri}}

+

Session ID: {{$fetchedQrCodeSessionId}}

+

Session Status: {{$fetchedQrCodeSessionStatus}}

+

Session Expiry: {{$fetchedQrCodeSessionExpiry}}

+
+ +
+

Fetched Session

+

Id: {{$fetchedSessionId}}

+

Created: {{$fetchedSessionCreated}}

+

Updated: {{$fetchedSessionUpdated}}

+

Expiry: {{$fetchedSessionExpiry}}

+

Status: {{$fetchedSessionStatus}}

+

QR Code ID: {{$fetchedSessionQrCodeId}}

+

Receipt ID: {{$fetchedSessionReceiptId}}

+
+ +
+
+ + + \ No newline at end of file diff --git a/src/Exception/IdentityException.php b/src/Exception/IdentityException.php new file mode 100644 index 00000000..0c235e8b --- /dev/null +++ b/src/Exception/IdentityException.php @@ -0,0 +1,9 @@ +wantedAnchors = $wantedAnchors; + + Validation::isBoolean($softPreference, 'soft_preference'); + $this->softPreference = $softPreference; + } + + public function jsonSerialize(): stdClass + { + return (object)[ + 'anchors' => $this->wantedAnchors, + 'soft_preference' => $this->softPreference, + ]; + } + + /** + * @return WantedAnchor[] + */ + public function getWantedAnchors(): array + { + return $this->wantedAnchors; + } + + /** + * @return bool + */ + public function isSoftPreference(): bool + { + return $this->softPreference; + } +} diff --git a/src/Identity/Constraint/SourceConstraint.php b/src/Identity/Constraint/SourceConstraint.php new file mode 100644 index 00000000..cd903789 --- /dev/null +++ b/src/Identity/Constraint/SourceConstraint.php @@ -0,0 +1,43 @@ +type = 'SOURCE'; + + Validation::isArrayOfType($wantedAnchors, [WantedAnchor::class], 'anchors'); + $this->preferredSources = new PreferredSources($wantedAnchors, $softPreference); + } + + public function getType(): string + { + return $this->type; + } + + public function getPreferredSources(): PreferredSources + { + return $this->preferredSources; + } + + public function jsonSerialize(): object + { + return (object)[ + 'type' => $this->getType(), + 'preferred_sources' => $this->getPreferredSources(), + ]; + } +} diff --git a/src/Identity/Constraint/SourceConstraintBuilder.php b/src/Identity/Constraint/SourceConstraintBuilder.php new file mode 100644 index 00000000..59b62e16 --- /dev/null +++ b/src/Identity/Constraint/SourceConstraintBuilder.php @@ -0,0 +1,46 @@ +wantedAnchors = $wantedAnchors; + + return $this; + } + + public function withWantedAnchor(WantedAnchor $wantedAnchor): self + { + $this->wantedAnchors[] = $wantedAnchor; + + return $this; + } + + public function withSoftPreference(bool $softPreference): self + { + $this->softPreference = $softPreference; + + return $this; + } + + public function build(): SourceConstraint + { + return new SourceConstraint($this->wantedAnchors, $this->softPreference); + } +} diff --git a/src/Identity/Extension/BasicExtensionBuilder.php b/src/Identity/Extension/BasicExtensionBuilder.php new file mode 100644 index 00000000..97d913aa --- /dev/null +++ b/src/Identity/Extension/BasicExtensionBuilder.php @@ -0,0 +1,40 @@ +type = $type; + + return $this; + } + + /** + * @param mixed $content + * + * @return $this + */ + public function withContent($content): self + { + $this->content = $content; + + return $this; + } + + public function build(): Extension + { + return new Extension($this->type, $this->content); + } +} diff --git a/src/Identity/Extension/Extension.php b/src/Identity/Extension/Extension.php new file mode 100644 index 00000000..d7e436b1 --- /dev/null +++ b/src/Identity/Extension/Extension.php @@ -0,0 +1,38 @@ +type = $type; + + Validation::notNull($type, 'content'); + $this->content = $content; + } + + /** + * @return stdClass + */ + public function jsonSerialize(): stdClass + { + return (object)[ + 'type' => $this->type, + 'content' => $this->content, + ]; + } +} diff --git a/src/Identity/Extension/ExtensionBuilderInterface.php b/src/Identity/Extension/ExtensionBuilderInterface.php new file mode 100644 index 00000000..1ab39bd8 --- /dev/null +++ b/src/Identity/Extension/ExtensionBuilderInterface.php @@ -0,0 +1,8 @@ +latitude = $latitude; + + Validation::withinRange($longitude, -180, 180, 'longitude'); + $this->longitude = $longitude; + + Validation::notLessThan($radius, 0, 'radius'); + $this->radius = $radius; + + Validation::notLessThan($maxUncertainty, 0, 'maxUncertainty'); + $this->maxUncertainty = $maxUncertainty; + } + + /** + * @inheritDoc + * + * @return stdClass + */ + public function jsonSerialize(): stdClass + { + return (object)[ + 'expected_device_location' => [ + 'latitude' => $this->latitude, + 'longitude' => $this->longitude, + 'radius' => $this->radius, + 'max_uncertainty_radius' => $this->maxUncertainty, + ] + ]; + } +} diff --git a/src/Identity/Extension/LocationConstraintExtensionBuilder.php b/src/Identity/Extension/LocationConstraintExtensionBuilder.php new file mode 100644 index 00000000..556cd19d --- /dev/null +++ b/src/Identity/Extension/LocationConstraintExtensionBuilder.php @@ -0,0 +1,82 @@ +latitude = $latitude; + return $this; + } + + /** + * Allows you to specify the Longitude of the user's expected location + */ + public function withLongitude(float $longitude): self + { + $this->longitude = $longitude; + return $this; + } + + /** + * Radius of the circle, centred on the specified location coordinates, where the device is + * allowed to perform the share. + * + * If not provided, a default value of 150m will be used. + * + * @param float $radius + * The allowable distance, in metres, from the given lat/long location + */ + public function withRadius(float $radius): self + { + $this->radius = $radius; + return $this; + } + + /** + * Maximum acceptable distance, in metres, of the area of uncertainty associated with the device + * location coordinates. + * + * If not provided, a default value of 150m will be used. + * + * @param float $maxUncertainty + * Maximum allowed measurement uncertainty, in metres + * + * @return $this + */ + public function withMaxUncertainty(float $maxUncertainty): self + { + $this->maxUncertainty = $maxUncertainty; + + return $this; + } + + public function build(): Extension + { + $content = new LocationConstraintContent( + $this->latitude, + $this->longitude, + $this->radius, + $this->maxUncertainty + ); + + return new Extension(self::LOCATION_CONSTRAINT, $content); + } +} diff --git a/src/Identity/Extension/ThirdPartyAttributeContent.php b/src/Identity/Extension/ThirdPartyAttributeContent.php new file mode 100644 index 00000000..0eeec95a --- /dev/null +++ b/src/Identity/Extension/ThirdPartyAttributeContent.php @@ -0,0 +1,38 @@ +expiryDate = $expiryDate; + + Validation::isArrayOfType($definitions, [AttributeDefinition::class], 'definitions'); + $this->definitions = $definitions; + } + + public function jsonSerialize(): stdClass + { + return (object)[ + 'expiry_date' => $this->expiryDate + ->setTimezone(new \DateTimeZone('UTC')) + ->format(\DateTime::RFC3339_EXTENDED), + 'definitions' => $this->definitions, + ]; + } +} diff --git a/src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php b/src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php new file mode 100644 index 00000000..132fa720 --- /dev/null +++ b/src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php @@ -0,0 +1,66 @@ +expiryDate = $expiryDate; + + return $this; + } + + public function withDefinition(string $definition): self + { + $this->definitions[] = new AttributeDefinition($definition); + + return $this; + } + + /** + * @param string[] $definitions + */ + public function withDefinitions(array $definitions): self + { + Validation::isArrayOfStrings($definitions, 'definitions'); + $this->definitions = array_map( + function ($definition): AttributeDefinition { + return new AttributeDefinition($definition); + }, + $definitions + ); + + return $this; + } + + public function build(): Extension + { + return new Extension( + self::THIRD_PARTY_ATTRIBUTE, + new ThirdPartyAttributeContent( + $this->expiryDate, + $this->definitions + ) + ); + } +} diff --git a/src/Identity/Extension/TransactionalFlowExtensionBuilder.php b/src/Identity/Extension/TransactionalFlowExtensionBuilder.php new file mode 100644 index 00000000..22eb5821 --- /dev/null +++ b/src/Identity/Extension/TransactionalFlowExtensionBuilder.php @@ -0,0 +1,35 @@ +content = $content; + + return $this; + } + + /** + * @return Extension with TRANSACTIONAL_FLOW type + */ + public function build(): Extension + { + return new Extension(static::TYPE, $this->content); + } +} diff --git a/src/Identity/IdentityService.php b/src/Identity/IdentityService.php new file mode 100644 index 00000000..edbf96f5 --- /dev/null +++ b/src/Identity/IdentityService.php @@ -0,0 +1,109 @@ +sdkId = $sdkId; + $this->pemFile = $pemFile; + $this->config = $config; + } + + public function createShareSession(ShareSessionRequest $shareSessionRequest): ShareSessionCreated + { + $response = (new RequestBuilder($this->config)) + ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) + ->withEndpoint(self::IDENTITY_SESSION_CREATION) + ->withHeader('X-Yoti-Auth-Id', $this->sdkId) + ->withPost() + ->withPayload(Payload::fromJsonData($shareSessionRequest)) + ->withPemFile($this->pemFile) + ->build() + ->execute(); + + $httpCode = $response->getStatusCode(); + if ($httpCode < 200 || $httpCode > 299) { + throw new IdentityException("Server responded with {$httpCode}", $response); + } + + return new ShareSessionCreated(Json::decode((string)$response->getBody())); + } + + public function createShareQrCode(string $sessionId): ShareSessionCreatedQrCode + { + $response = (new RequestBuilder($this->config)) + ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) + ->withEndpoint(sprintf(self::IDENTITY_SESSION_QR_CODE_CREATION, $sessionId)) + ->withHeader('X-Yoti-Auth-Id', $this->sdkId) + ->withPost() + ->withPemFile($this->pemFile) + ->build() + ->execute(); + + $httpCode = $response->getStatusCode(); + if ($httpCode < 200 || $httpCode > 299) { + throw new IdentityException("Server responded with {$httpCode}", $response); + } + + return new ShareSessionCreatedQrCode(Json::decode((string)$response->getBody())); + } + + public function fetchShareQrCode(string $qrCodeId): ShareSessionFetchedQrCode + { + $response = (new RequestBuilder($this->config)) + ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) + ->withEndpoint(sprintf(self::IDENTITY_SESSION_QR_CODE_RETRIEVAL, $qrCodeId)) + ->withHeader('X-Yoti-Auth-Id', $this->sdkId) + ->withPost() + ->withPemFile($this->pemFile) + ->build() + ->execute(); + + $httpCode = $response->getStatusCode(); + if ($httpCode < 200 || $httpCode > 299) { + throw new IdentityException("Server responded with {$httpCode}", $response); + } + + return new ShareSessionFetchedQrCode(Json::decode((string)$response->getBody())); + } + + public function fetchShareSession(string $sessionId): ShareSessionFetched + { + $response = (new RequestBuilder($this->config)) + ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) + ->withEndpoint(sprintf(self::IDENTITY_SESSION_RETRIEVAL, $sessionId)) + ->withHeader('X-Yoti-Auth-Id', $this->sdkId) + ->withPost() + ->withPemFile($this->pemFile) + ->build() + ->execute(); + + $httpCode = $response->getStatusCode(); + if ($httpCode < 200 || $httpCode > 299) { + throw new IdentityException("Server responded with {$httpCode}", $response); + } + + return new ShareSessionFetched(Json::decode((string)$response->getBody())); + } +} diff --git a/src/Identity/Policy/Policy.php b/src/Identity/Policy/Policy.php new file mode 100644 index 00000000..62ade060 --- /dev/null +++ b/src/Identity/Policy/Policy.php @@ -0,0 +1,75 @@ +wantedAttributes = $wantedAttributes; + + Validation::isArrayOfIntegers($wantedAuthTypes, 'wantedAuthTypes'); + $this->wantedAuthTypes = $wantedAuthTypes; + + $this->wantedRememberMe = $wantedRememberMe; + $this->wantedRememberMeOptional = $wantedRememberMeOptional; + $this->identityProfileRequirements = $identityProfileRequirements; + } + + + public function jsonSerialize(): stdClass + { + return (object)[ + 'wanted' => $this->wantedAttributes, + 'wanted_auth_types' => $this->wantedAuthTypes, + 'wanted_remember_me' => $this->wantedRememberMe, + 'wanted_remember_me_optional' => $this->wantedRememberMeOptional, + 'identity_profile_requirements' => $this->identityProfileRequirements, + ]; + } + + /** + * IdentityProfileRequirements requested in the policy + * + * @return object|null + */ + public function getIdentityProfileRequirements() + { + return $this->identityProfileRequirements; + } +} diff --git a/src/Identity/Policy/PolicyBuilder.php b/src/Identity/Policy/PolicyBuilder.php new file mode 100644 index 00000000..e8a8b190 --- /dev/null +++ b/src/Identity/Policy/PolicyBuilder.php @@ -0,0 +1,332 @@ +getName(); + + if (null !== $wantedAttribute->getDerivation()) { + $key = $wantedAttribute->getDerivation(); + } + + if (null !== $wantedAttribute->getConstraints()) { + $key .= '-' . hash('sha256', Json::encode($wantedAttribute->getConstraints())); + } + + $this->wantedAttributes[$key] = $wantedAttribute; + + return $this; + } + + /** + * @param Constraint[]|null $constraints + */ + public function withWantedAttributeByName( + string $name, + array $constraints = null, + bool $acceptSelfAsserted = null + ): self { + $wantedAttributeBuilder = (new WantedAttributeBuilder()) + ->withName($name); + + if ($constraints !== null) { + $wantedAttributeBuilder->withConstraints($constraints); + } + + if ($acceptSelfAsserted !== null) { + $wantedAttributeBuilder->withAcceptSelfAsserted($acceptSelfAsserted); + } + + return $this->withWantedAttribute($wantedAttributeBuilder->build()); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withFamilyName(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_FAMILY_NAME, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withGivenNames(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_GIVEN_NAMES, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withFullName(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_FULL_NAME, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withDateOfBirth(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_DATE_OF_BIRTH, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withAgeOver(int $age, array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withAgeDerivedAttribute( + UserProfile::AGE_OVER . $age, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withAgeUnder(int $age, array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withAgeDerivedAttribute( + UserProfile::AGE_UNDER . $age, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withAgeDerivedAttribute( + string $derivation, + array $constraints = null, + bool $acceptSelfAsserted = null + ): self { + $wantedAttributeBuilder = (new WantedAttributeBuilder()) + ->withName(UserProfile::ATTR_DATE_OF_BIRTH) + ->withDerivation($derivation); + + if ($constraints !== null) { + $wantedAttributeBuilder->withConstraints($constraints); + } + + if ($acceptSelfAsserted !== null) { + $wantedAttributeBuilder->withAcceptSelfAsserted($acceptSelfAsserted); + } + + return $this->withWantedAttribute($wantedAttributeBuilder->build()); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withGender(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_GENDER, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withPostalAddress(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_POSTAL_ADDRESS, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withStructuredPostalAddress(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_STRUCTURED_POSTAL_ADDRESS, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withNationality(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_NATIONALITY, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withPhoneNumber(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_PHONE_NUMBER, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withSelfie(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_SELFIE, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withDocumentDetails(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_DOCUMENT_DETAILS, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withDocumentImages(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_DOCUMENT_IMAGES, + $constraints, + $acceptSelfAsserted + ); + } + + /** + * @param Constraint[]|null $constraints + */ + public function withEmail(array $constraints = null, bool $acceptSelfAsserted = null): self + { + return $this->withWantedAttributeByName( + UserProfile::ATTR_EMAIL_ADDRESS, + $constraints, + $acceptSelfAsserted + ); + } + + + public function withSelfieAuthentication(bool $enabled = true): self + { + return $this->withWantedAuthType(self::SELFIE_AUTH_TYPE, $enabled); + } + + + public function withPinAuthentication(bool $enabled = true): self + { + return $this->withWantedAuthType(self::PIN_AUTH_TYPE, $enabled); + } + + public function withWantedAuthType(int $wantedAuthType, bool $enabled = true): self + { + if ($enabled) { + $this->wantedAuthTypes[$wantedAuthType] = $wantedAuthType; + } else { + unset($this->wantedAuthTypes[$wantedAuthType]); + } + + return $this; + } + + + public function withWantedRememberMe(bool $wantedRememberMe): self + { + $this->wantedRememberMe = $wantedRememberMe; + return $this; + } + + public function withWantedRememberMeOptional(bool $wantedRememberMeOptional): self + { + $this->wantedRememberMeOptional = $wantedRememberMeOptional; + return $this; + } + + /** + * Use an Identity Profile Requirement object for the share + * + * @param object $identityProfileRequirements + * @return $this + */ + public function withIdentityProfileRequirements($identityProfileRequirements): self + { + $this->identityProfileRequirements = $identityProfileRequirements; + return $this; + } + + + public function build(): Policy + { + return new Policy( + array_values($this->wantedAttributes), + array_values($this->wantedAuthTypes), + $this->wantedRememberMe, + $this->wantedRememberMeOptional, + $this->identityProfileRequirements + ); + } +} diff --git a/src/Identity/Policy/WantedAnchor.php b/src/Identity/Policy/WantedAnchor.php new file mode 100644 index 00000000..1714ca8a --- /dev/null +++ b/src/Identity/Policy/WantedAnchor.php @@ -0,0 +1,29 @@ +value = $value; + $this->subType = $subType; + } + + public function jsonSerialize(): stdClass + { + return (object)[ + 'name' => $this->value, + 'sub_type' => $this->subType, + ]; + } +} diff --git a/src/Identity/Policy/WantedAnchorBuilder.php b/src/Identity/Policy/WantedAnchorBuilder.php new file mode 100644 index 00000000..9625445f --- /dev/null +++ b/src/Identity/Policy/WantedAnchorBuilder.php @@ -0,0 +1,32 @@ +value = $value; + return $this; + } + + public function withSubType(string $subType): self + { + $this->subType = $subType; + return $this; + } + + public function build(): WantedAnchor + { + Validation::notNull($this->value, 'value'); + Validation::notNull($this->subType, 'sub_type'); + + return new WantedAnchor($this->value, $this->subType); + } +} diff --git a/src/Identity/Policy/WantedAttribute.php b/src/Identity/Policy/WantedAttribute.php new file mode 100644 index 00000000..dc34da79 --- /dev/null +++ b/src/Identity/Policy/WantedAttribute.php @@ -0,0 +1,123 @@ +name = $name; + + $this->derivation = $derivation; + $this->optional = $optional; + $this->acceptSelfAsserted = $acceptSelfAsserted; + + if (null !== $constraints) { + Validation::isArrayOfType($constraints, [Constraint::class], 'constraints'); + $this->constraints = $constraints; + } + } + + /** + * Name identifying the WantedAttribute + * + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * Additional derived criteria. + * + * @return string + */ + public function getDerivation(): ?string + { + return $this->derivation; + } + + /** + * List of constraints to add to an attribute. + * + * If you do not provide any particular constraints, Yoti will provide you with the + * information from the most recently added source. + * + * @return Constraint[] $constraints + */ + public function getConstraints(): ?array + { + return $this->constraints; + } + + /** + * Accept self asserted attributes. + * + * These are attributes that have been self-declared, and not verified by Yoti. + * + * @return bool|null + */ + public function getAcceptSelfAsserted(): ?bool + { + return $this->acceptSelfAsserted; + } + + /** + * @return bool + */ + public function getOptional(): bool + { + return $this->optional; + } + + public function jsonSerialize(): stdClass + { + $data = new stdClass(); + $data->name = $this->getName(); + $data->optional = $this->getOptional(); + + if (null !== $this->getDerivation()) { + $data->derivation = $this->getDerivation(); + } + + if (null !== $this->getConstraints()) { + $data->constraints = $this->getConstraints(); + } + + if (null !== $this->getAcceptSelfAsserted()) { + $data->accept_self_asserted = $this->getAcceptSelfAsserted(); + } + + return $data; + } +} diff --git a/src/Identity/Policy/WantedAttributeBuilder.php b/src/Identity/Policy/WantedAttributeBuilder.php new file mode 100644 index 00000000..c2a53f1f --- /dev/null +++ b/src/Identity/Policy/WantedAttributeBuilder.php @@ -0,0 +1,77 @@ +name = $name; + + return $this; + } + + public function withDerivation(string $derivation): self + { + $this->derivation = $derivation; + + return $this; + } + + public function withOptional(bool $optional): self + { + $this->optional = $optional; + + return $this; + } + + public function withAcceptSelfAsserted(bool $acceptSelfAsserted): self + { + $this->acceptSelfAsserted = $acceptSelfAsserted; + + return $this; + } + + /** + * @param Constraint[] $constraints + */ + public function withConstraints(array $constraints): self + { + $this->constraints = $constraints; + + return $this; + } + + public function withConstraint(Constraint $constraint): self + { + $this->constraints[] = $constraint; + + return $this; + } + + public function build(): WantedAttribute + { + return new WantedAttribute( + $this->name, + $this->derivation, + $this->optional, + $this->acceptSelfAsserted, + $this->constraints, + ); + } +} diff --git a/src/Identity/ShareSessionCreated.php b/src/Identity/ShareSessionCreated.php new file mode 100644 index 00000000..4bb0f924 --- /dev/null +++ b/src/Identity/ShareSessionCreated.php @@ -0,0 +1,71 @@ +id = $sessionData['id']; + } + + if (isset($sessionData['status'])) { + Validation::isString($sessionData['status'], 'status'); + $this->status = $sessionData['status']; + } + + if (isset($sessionData['expiry'])) { + Validation::isString($sessionData['expiry'], 'expiry'); + $this->expiry = $sessionData['expiry']; + } + } + + /** + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return string + */ + public function getExpiry(): string + { + return $this->expiry; + } + + public function jsonSerialize(): object + { + return (object)[ + 'id' => $this->getId(), + 'status' => $this->getStatus(), + 'expiry' => $this->getExpiry(), + ]; + } +} diff --git a/src/Identity/ShareSessionCreatedQrCode.php b/src/Identity/ShareSessionCreatedQrCode.php new file mode 100644 index 00000000..901074b0 --- /dev/null +++ b/src/Identity/ShareSessionCreatedQrCode.php @@ -0,0 +1,48 @@ +id = $sessionData['id']; + } + + if (isset($sessionData['uri'])) { + $this->uri = $sessionData['uri']; + } + } + + public function jsonSerialize(): object + { + return (object)[ + 'id' => $this->id, + 'uri' => $this->uri + ]; + } + + /** + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * @return string + */ + public function getUri(): string + { + return $this->uri; + } +} diff --git a/src/Identity/ShareSessionFetched.php b/src/Identity/ShareSessionFetched.php new file mode 100644 index 00000000..ac171a2f --- /dev/null +++ b/src/Identity/ShareSessionFetched.php @@ -0,0 +1,117 @@ + $sessionData + */ + public function __construct(array $sessionData) + { + if (isset($sessionData['id'])) { + $this->id = $sessionData['id']; + } + if (isset($sessionData['status'])) { + $this->status = $sessionData['status']; + } + if (isset($sessionData['expiry'])) { + $this->expiry = $sessionData['expiry']; + } + if (isset($sessionData['created'])) { + $this->created = $sessionData['created']; + } + if (isset($sessionData['updated'])) { + $this->updated = $sessionData['updated']; + } + if (isset($sessionData['qrCode'])) { + $this->qrCodeId = $sessionData['qrCode']['id']; + } + if (isset($sessionData['receipt'])) { + $this->receiptId = $sessionData['receipt']['id']; + } + } + + public function jsonSerialize(): object + { + return (object)[ + 'id' => $this->id, + 'status' => $this->status, + 'expiry' => $this->expiry, + 'created' => $this->created, + 'updated' => $this->updated, + 'qrCodeId' => $this->qrCodeId, + 'receiptId' => $this->receiptId, + ]; + } + + /** + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return string + */ + public function getCreated(): string + { + return $this->created; + } + + /** + * @return string + */ + public function getUpdated(): string + { + return $this->updated; + } + + /** + * @return string + */ + public function getExpiry(): string + { + return $this->expiry; + } + + /** + * @return string + */ + public function getQrCodeId(): string + { + return $this->qrCodeId; + } + + /** + * @return string + */ + public function getReceiptId(): string + { + return $this->receiptId; + } +} diff --git a/src/Identity/ShareSessionFetchedQrCode.php b/src/Identity/ShareSessionFetchedQrCode.php new file mode 100644 index 00000000..1f8aaabf --- /dev/null +++ b/src/Identity/ShareSessionFetchedQrCode.php @@ -0,0 +1,110 @@ + $sessionData + */ + public function __construct(array $sessionData) + { + if (isset($sessionData['id'])) { + $this->id = $sessionData['id']; + } + if (isset($sessionData['expiry'])) { + $this->expiry = $sessionData['expiry']; + } + if (isset($sessionData['policy'])) { + $this->policy = $sessionData['policy']; + } + if (isset($sessionData['extensions'])) { + foreach ($sessionData['extensions'] as $extension) { + $this->extensions[] = new Extension($extension['type'], $extension['content']); + } + } + if (isset($sessionData['session'])) { + $this->session = new ShareSessionCreated($sessionData['session']); + } + if (isset($sessionData['redirectUri'])) { + $this->redirectUri = $sessionData['redirectUri']; + } + } + + public function jsonSerialize(): object + { + return (object)[ + 'id' => $this->id, + 'expiry' => $this->expiry, + 'policy' => $this->policy, + 'extensions' => $this->extensions, + 'session' => $this->session, + 'redirectUri' => $this->redirectUri, + ]; + } + + /** + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * @return string + */ + public function getExpiry(): string + { + return $this->expiry; + } + + /** + * @return string + */ + public function getPolicy(): string + { + return $this->policy; + } + + /** + * @return Extension[] + */ + public function getExtensions(): array + { + return $this->extensions; + } + + /** + * @return ShareSessionCreated + */ + public function getSession(): ShareSessionCreated + { + return $this->session; + } + + /** + * @return string + */ + public function getRedirectUri(): string + { + return $this->redirectUri; + } +} diff --git a/src/Identity/ShareSessionNotification.php b/src/Identity/ShareSessionNotification.php new file mode 100644 index 00000000..5a6fc24f --- /dev/null +++ b/src/Identity/ShareSessionNotification.php @@ -0,0 +1,70 @@ + + */ + private array $headers; + + /** + * @param string[] $headers + */ + public function __construct(string $url, string $method, bool $verifyTls, array $headers) + { + $this->url = $url; + $this->method = $method; + $this->verifyTls = $verifyTls; + $this->headers = $headers; + } + + public function jsonSerialize(): object + { + return (object)[ + 'url' => $this->getUrl(), + 'method' => $this->getMethod(), + 'verifyTls' => $this->isVerifyTls(), + 'headers' => $this->getHeaders(), + ]; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getMethod(): string + { + return $this->method; + } + + /** + * @return bool + */ + public function isVerifyTls(): bool + { + return $this->verifyTls; + } + + /** + * @return string[] + */ + public function getHeaders(): array + { + return $this->headers; + } +} diff --git a/src/Identity/ShareSessionNotificationBuilder.php b/src/Identity/ShareSessionNotificationBuilder.php new file mode 100644 index 00000000..39d7aba3 --- /dev/null +++ b/src/Identity/ShareSessionNotificationBuilder.php @@ -0,0 +1,65 @@ + + */ + private array $headers; + + public function withUrl(string $url): self + { + $this->url = $url; + + return $this; + } + + public function withMethod(string $method = 'POST'): self + { + $this->method = $method; + + return $this; + } + + public function withVerifyTls(bool $verifyTls = true): self + { + $this->verifyTls = $verifyTls; + + return $this; + } + + /** + * @param string[] $headers + */ + public function withHeaders(array $headers): self + { + $this->headers = $headers; + + return $this; + } + + public function withHeader(string $key, string $header): self + { + $this->headers[$key] = $header; + + return $this; + } + + public function build(): ShareSessionNotification + { + return new ShareSessionNotification( + $this->url, + $this->method, + $this->verifyTls, + $this->headers + ); + } +} diff --git a/src/Identity/ShareSessionRequest.php b/src/Identity/ShareSessionRequest.php new file mode 100644 index 00000000..94e9cadb --- /dev/null +++ b/src/Identity/ShareSessionRequest.php @@ -0,0 +1,110 @@ +|null + */ + private ?array $subject; + + private Policy $policy; + + /** + * @var Extension[]|null + */ + private ?array $extensions = null; + + private string $redirectUri; + + private ?ShareSessionNotification $notification; + + /** + * @param array|null $subject + * @param Policy $policy + * @param Extension[]|null $extensions + * @param string $redirectUri + * @param ShareSessionNotification|null $notification + */ + public function __construct( + Policy $policy, + string $redirectUri, + ?array $extensions = null, + ?array $subject = null, + ?ShareSessionNotification $notification = null + ) { + $this->policy = $policy; + $this->redirectUri = $redirectUri; + + if (null !== $extensions) { + Validation::isArrayOfType($extensions, [Extension::class], 'extensions'); + $this->extensions = $extensions; + } + + $this->subject = $subject; + $this->notification = $notification; + } + + /** + * @return array|null + */ + public function getSubject(): ?array + { + return $this->subject; + } + + /** + * @return Policy + */ + public function getPolicy(): Policy + { + return $this->policy; + } + + /** + * @return Extension[]|null + */ + public function getExtensions(): ?array + { + return $this->extensions; + } + + /** + * @return string + */ + public function getRedirectUri(): string + { + return $this->redirectUri; + } + + /** + * @return ShareSessionNotification|null + */ + public function getNotification(): ?ShareSessionNotification + { + return $this->notification; + } + + public function jsonSerialize(): \stdClass + { + $data = new \stdClass(); + $data->policy = $this->getPolicy(); + $data->redirectUri = $this->getRedirectUri(); + if (null !== $this->getSubject()) { + $data->subject = $this->getSubject(); + } + if (null !== $this->getExtensions()) { + $data->extensions = $this->getExtensions(); + } + if (null !== $this->getNotification()) { + $data->notification = $this->getNotification(); + } + + return $data; + } +} diff --git a/src/Identity/ShareSessionRequestBuilder.php b/src/Identity/ShareSessionRequestBuilder.php new file mode 100644 index 00000000..583d06fe --- /dev/null +++ b/src/Identity/ShareSessionRequestBuilder.php @@ -0,0 +1,84 @@ + + */ + private ?array $subject = null; + + private Policy $policy; + + /** + * @var Extension[] + */ + private ?array $extensions = null; + + private string $redirectUri; + + private ?ShareSessionNotification $notification = null; + + /** + * @param array $subject + */ + public function withSubject(array $subject): self + { + $this->subject = $subject; + + return $this; + } + + public function withPolicy(Policy $policy): self + { + $this->policy = $policy; + + return $this; + } + + /** + * @param Extension[] $extensions + */ + public function withExtensions(array $extensions): self + { + $this->extensions = $extensions; + + return $this; + } + + public function withExtension(Extension $extension): self + { + $this->extensions[] = $extension; + + return $this; + } + + public function withRedirectUri(string $redirectUri): self + { + $this->redirectUri = $redirectUri; + + return $this; + } + + public function withNotification(ShareSessionNotification $notification): ShareSessionRequestBuilder + { + $this->notification = $notification; + + return $this; + } + + public function build(): ShareSessionRequest + { + return new ShareSessionRequest( + $this->policy, + $this->redirectUri, + $this->extensions, + $this->subject, + $this->notification + ); + } +} diff --git a/src/Util/Validation.php b/src/Util/Validation.php index 1bfbb82c..c998db56 100644 --- a/src/Util/Validation.php +++ b/src/Util/Validation.php @@ -40,7 +40,7 @@ public static function isBoolean($value, $name): void */ public static function notNull($value, string $name): void { - if (is_null($value)) { + if (null === $value) { throw new \InvalidArgumentException("{$name} cannot be null"); } } diff --git a/src/YotiClient.php b/src/YotiClient.php index 54caf6bc..c706ca37 100644 --- a/src/YotiClient.php +++ b/src/YotiClient.php @@ -8,8 +8,11 @@ use Yoti\Aml\Result as AmlResult; use Yoti\Aml\Service as AmlService; use Yoti\Exception\ActivityDetailsException; +use Yoti\Exception\IdentityException; use Yoti\Exception\PemFileException; use Yoti\Exception\ReceiptException; +use Yoti\Identity\IdentityService; +use Yoti\Identity\ShareSessionRequest; use Yoti\Profile\ActivityDetails; use Yoti\Profile\Service as ProfileService; use Yoti\ShareUrl\DynamicScenario; @@ -28,20 +31,13 @@ */ class YotiClient { - /** - * @var AmlService - */ - private $amlService; + private AmlService $amlService; - /** - * @var ProfileService - */ - private $profileService; + private ProfileService $profileService; - /** - * @var ShareUrlService - */ - private $shareUrlService; + private ShareUrlService $shareUrlService; + + private IdentityService $identityService; /** * YotiClient constructor. @@ -71,6 +67,7 @@ public function __construct( $this->profileService = new ProfileService($sdkId, $pemFile, $config); $this->amlService = new AmlService($sdkId, $pemFile, $config); $this->shareUrlService = new ShareUrlService($sdkId, $pemFile, $config); + $this->identityService = new IdentityService($sdkId, $pemFile, $config); } /** @@ -129,4 +126,52 @@ public function createShareUrl(DynamicScenario $dynamicScenario): ShareUrlResult { return $this->shareUrlService->createShareUrl($dynamicScenario); } + + /** + * Create a sharing session to initiate a sharing process based on a policy + * + * @throws IdentityException + * + * Aggregate exception signalling issues during the call + */ + public function createShareSession(ShareSessionRequest $request): Identity\ShareSessionCreated + { + return $this->identityService->createShareSession($request); + } + + /** + * Create a sharing session QR code to initiate a sharing process based on a policy + * + * @throws IdentityException + * + * Aggregate exception signalling issues during the call + */ + public function createShareQrCode(string $sessionId): Identity\ShareSessionCreatedQrCode + { + return $this->identityService->createShareQrCode($sessionId); + } + + /** + * Retrieve the sharing session QR code + * + * @throws IdentityException + * + * Aggregate exception signalling issues during the call + */ + public function fetchShareQrCode(string $qrCodeId): Identity\ShareSessionFetchedQrCode + { + return $this->identityService->fetchShareQrCode($qrCodeId); + } + + /** + * Retrieve the sharing session + * + * @throws IdentityException + * + * Aggregate exception signalling issues during the call + */ + public function fetchShareSession(string $sessionId): Identity\ShareSessionFetched + { + return $this->identityService->fetchShareSession($sessionId); + } } diff --git a/tests/Identity/Constraint/PreferredSourcesTest.php b/tests/Identity/Constraint/PreferredSourcesTest.php new file mode 100644 index 00000000..8b5b4ff1 --- /dev/null +++ b/tests/Identity/Constraint/PreferredSourcesTest.php @@ -0,0 +1,42 @@ + $wantedAnchors, + 'soft_preference' => true + ]; + + $this->assertInstanceOf(PreferredSources::class, $preferredSource); + $this->assertEquals(json_encode($expected), json_encode($preferredSource)); + $this->assertEquals($wantedAnchors, $preferredSource->getWantedAnchors()); + $this->assertTrue($preferredSource->isSoftPreference()); + } +} diff --git a/tests/Identity/Constraint/SourceConstraintsBuilderTest.php b/tests/Identity/Constraint/SourceConstraintsBuilderTest.php new file mode 100644 index 00000000..ac6423c6 --- /dev/null +++ b/tests/Identity/Constraint/SourceConstraintsBuilderTest.php @@ -0,0 +1,66 @@ +withWantedAnchor(new WantedAnchor('SOME_VALUE')) + ->withSoftPreference(true) + ->build(); + + $this->assertInstanceOf(SourceConstraint::class, $sourceConstraint); + $this->assertInstanceOf(PreferredSources::class, $sourceConstraint->getPreferredSources()); + $this->assertEquals('SOURCE', $sourceConstraint->getType()); + } + + /** + * @covers ::build + * @covers ::withWantedAnchors + * @covers \Yoti\Identity\Constraint\SourceConstraint::__construct + * @covers \Yoti\Identity\Constraint\SourceConstraint::jsonSerialize + */ + public function testShouldBuildCorrectlyWithMultipleAnchors() + { + $wantedAnchors = [ + new WantedAnchor('some'), + new WantedAnchor('some_2'), + ]; + + $sourceConstraint = (new SourceConstraintBuilder()) + ->withWantedAnchors($wantedAnchors) + ->build(); + + $expectedConstraint = [ + 'type' => 'SOURCE', + 'preferred_sources' => $sourceConstraint->getPreferredSources() + ]; + + $this->assertEquals($wantedAnchors, $sourceConstraint->getPreferredSources()->getWantedAnchors()); + $this->assertEquals( + json_encode($wantedAnchors), + json_encode($sourceConstraint->getPreferredSources()->getWantedAnchors()) + ); + $this->assertEquals(json_encode($expectedConstraint), json_encode($sourceConstraint)); + } +} diff --git a/tests/Identity/Extension/BasicExtensionBuilderTest.php b/tests/Identity/Extension/BasicExtensionBuilderTest.php new file mode 100644 index 00000000..026a045f --- /dev/null +++ b/tests/Identity/Extension/BasicExtensionBuilderTest.php @@ -0,0 +1,40 @@ +withType($someType) + ->withContent($someContent) + ->build(); + + $expectedJson = json_encode([ + 'type' => $someType, + 'content' => $someContent, + ]); + + $this->assertEquals($expectedJson, json_encode($constraints)); + } +} diff --git a/tests/Identity/Extension/LocationConstraintContentTest.php b/tests/Identity/Extension/LocationConstraintContentTest.php new file mode 100644 index 00000000..a0973db1 --- /dev/null +++ b/tests/Identity/Extension/LocationConstraintContentTest.php @@ -0,0 +1,44 @@ + [ + 'latitude' => $expectedLatitude, + 'longitude' => $expectedLongitude, + 'radius' => $expectedRadius, + 'max_uncertainty_radius' => $expectedMaxUncertainty, + ], + ]); + + $this->assertEquals($expectedJson, json_encode($content)); + } +} diff --git a/tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php b/tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php new file mode 100644 index 00000000..875b8bb7 --- /dev/null +++ b/tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php @@ -0,0 +1,164 @@ +expectException(\RangeException::class); + $this->expectExceptionMessage('\'latitude\' value \'-91\' is less than \'-90\''); + + (new LocationConstraintExtensionBuilder()) + ->withLatitude(-91) + ->withLongitude(0) + ->build(); + } + + /** + * @covers ::withLatitude + */ + public function testLatitudeTooHigh() + { + $this->expectException(\RangeException::class); + $this->expectExceptionMessage('\'latitude\' value \'91\' is greater than \'90\''); + + (new LocationConstraintExtensionBuilder()) + ->withLatitude(91) + ->withLongitude(0) + ->build(); + } + + /** + * @covers ::withLongitude + */ + public function testLongitudeTooLow() + { + $this->expectException(\RangeException::class); + $this->expectExceptionMessage('\'longitude\' value \'-181\' is less than \'-180\''); + + (new LocationConstraintExtensionBuilder()) + ->withLatitude(0) + ->withLongitude(-181) + ->build(); + } + + /** + * @covers ::withLongitude + */ + public function testLongitudeTooHigh() + { + $this->expectException(\RangeException::class); + $this->expectExceptionMessage('\'longitude\' value \'181\' is greater than \'180\''); + + (new LocationConstraintExtensionBuilder()) + ->withLatitude(0) + ->withLongitude(181) + ->build(); + } + + /** + * @covers ::withRadius + */ + public function testRadiusLessThanZero() + { + $this->expectException(\RangeException::class); + $this->expectExceptionMessage('\'radius\' value \'-1\' is less than \'0\''); + + (new LocationConstraintExtensionBuilder()) + ->withLatitude(0) + ->withLongitude(0) + ->withRadius(-1) + ->build(); + } + + /** + * @covers ::withMaxUncertainty + */ + public function testMaxUncertaintyLessThanZero() + { + $this->expectException(\RangeException::class); + $this->expectExceptionMessage('\'maxUncertainty\' value \'-1\' is less than \'0\''); + + (new LocationConstraintExtensionBuilder()) + ->withLatitude(0) + ->withLongitude(0) + ->withMaxUncertainty(-1) + ->build(); + } + + /** + * @covers ::build + */ + public function testBuild() + { + $expectedLatitude = 50.8169; + $expectedLongitude = -0.1367; + $expectedRadius = 30; + $expectedMaxUncertainty = 40; + + $extension = (new LocationConstraintExtensionBuilder()) + ->withLatitude($expectedLatitude) + ->withLongitude($expectedLongitude) + ->withRadius($expectedRadius) + ->withMaxUncertainty($expectedMaxUncertainty) + ->build(); + + $expectedJson = json_encode([ + 'type' => self::TYPE_LOCATION_CONSTRAINT, + 'content' => [ + 'expected_device_location' => [ + 'latitude' => $expectedLatitude, + 'longitude' => $expectedLongitude, + 'radius' => $expectedRadius, + 'max_uncertainty_radius' => $expectedMaxUncertainty, + ], + ], + ]); + + $this->assertEquals($expectedJson, json_encode($extension)); + } + + /** + * @covers ::build + */ + public function testBuildDefaultValues() + { + $expectedLatitude = 50.8169; + $expectedLongitude = -0.1367; + $expectedDefaultRadius = 150; + $expectedDefaultMaxUncertainty = 150; + + $extension = (new LocationConstraintExtensionBuilder()) + ->withLatitude($expectedLatitude) + ->withLongitude($expectedLongitude) + ->build(); + + $expectedJson = json_encode([ + 'type' => self::TYPE_LOCATION_CONSTRAINT, + 'content' => [ + 'expected_device_location' => [ + 'latitude' => $expectedLatitude, + 'longitude' => $expectedLongitude, + 'radius' => $expectedDefaultRadius, + 'max_uncertainty_radius' => $expectedDefaultMaxUncertainty, + ], + ], + ]); + + $this->assertEquals($expectedJson, json_encode($extension)); + } +} diff --git a/tests/Identity/Extension/ThirdPartyAttributeContentTest.php b/tests/Identity/Extension/ThirdPartyAttributeContentTest.php new file mode 100644 index 00000000..4fe6b729 --- /dev/null +++ b/tests/Identity/Extension/ThirdPartyAttributeContentTest.php @@ -0,0 +1,42 @@ + '2019-12-02T12:00:00.123+00:00', + 'definitions' => [ + [ + 'name' => $someDefinition, + ], + ], + ]); + + $this->assertEquals($expectedJson, json_encode($thirdPartyAttributeContent)); + } +} diff --git a/tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php b/tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php new file mode 100644 index 00000000..43252040 --- /dev/null +++ b/tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php @@ -0,0 +1,132 @@ +someDate = new \DateTime(self::SOME_DATE_STRING); + } + + /** + * @covers ::withExpiryDate + * @covers ::withDefinition + * @covers ::build + */ + public function testBuild() + { + $thirdPartyAttributeExtension = (new ThirdPartyAttributeExtensionBuilder()) + ->withExpiryDate($this->someDate) + ->withDefinition(self::SOME_DEFINITION) + ->withDefinition(self::SOME_OTHER_DEFINITION) + ->build(); + + $expectedJson = $this->createExpectedJson( + $this->someDate->format(\DateTime::RFC3339_EXTENDED), + [ + self::SOME_DEFINITION, + self::SOME_OTHER_DEFINITION, + ] + ); + + $this->assertJsonStringEqualsJsonString( + $expectedJson, + json_encode($thirdPartyAttributeExtension) + ); + } + + /** + * @covers ::withDefinitions + */ + public function testWithDefinitionsOverwritesExistingDefinitions() + { + $thirdPartyAttributeExtension = (new ThirdPartyAttributeExtensionBuilder()) + ->withExpiryDate($this->someDate) + ->withDefinition('initial definition') + ->withDefinitions([ + self::SOME_DEFINITION, + self::SOME_OTHER_DEFINITION, + ]) + ->build(); + + $this->assertJsonStringEqualsJsonString( + $this->createExpectedJson( + $this->someDate->format(\DateTime::RFC3339_EXTENDED), + [ + self::SOME_DEFINITION, + self::SOME_OTHER_DEFINITION, + ] + ), + json_encode($thirdPartyAttributeExtension) + ); + } + + /** + * @covers ::withExpiryDate + * + * @dataProvider expiryDateDataProvider + */ + public function testWithExpiryDateFormat($inputDate, $outputDate) + { + $thirdPartyAttributeExtension = (new ThirdPartyAttributeExtensionBuilder()) + ->withExpiryDate(new \DateTime($inputDate)) + ->build(); + + $this->assertJsonStringEqualsJsonString( + $this->createExpectedJson($outputDate, []), + json_encode($thirdPartyAttributeExtension) + ); + } + + /** + * Provides test expiry dates. + */ + public function expiryDateDataProvider(): array + { + return [ + ['2020-01-02T01:02:03.123456Z', '2020-01-02T01:02:03.123+00:00'], + ['2020-01-01T01:02:03.123+04:00', '2019-12-31T21:02:03.123+00:00'], + ['2020-01-02T01:02:03.123-02:00', '2020-01-02T03:02:03.123+00:00'] + ]; + } + + /** + * Create expected third party extension JSON. + * + * @param string $expiryDate + * @param string[] $definitions + * + * @return string + */ + private function createExpectedJson(string $expiryDate, array $definitions): string + { + return json_encode([ + 'type' => self::THIRD_PARTY_ATTRIBUTE_TYPE, + 'content' => [ + 'expiry_date' => $expiryDate, + 'definitions' => array_map( + function ($definition) { + return [ 'name' => $definition ]; + }, + $definitions + ), + ], + ]); + } +} diff --git a/tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php b/tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php new file mode 100644 index 00000000..6ad50610 --- /dev/null +++ b/tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php @@ -0,0 +1,36 @@ + 'content']; + + $constraints = (new TransactionalFlowExtensionBuilder()) + ->withContent($someContent) + ->build(); + + $expectedJson = json_encode([ + 'type' => self::TYPE_TRANSACTIONAL_FLOW, + 'content' => $someContent, + ]); + + $this->assertEquals($expectedJson, json_encode($constraints)); + } +} diff --git a/tests/Identity/IdentityServiceTest.php b/tests/Identity/IdentityServiceTest.php new file mode 100644 index 00000000..98b3cc08 --- /dev/null +++ b/tests/Identity/IdentityServiceTest.php @@ -0,0 +1,133 @@ +extensionMock = $this->createMock(Extension::class); + $this->policyMock = $this->createMock(Policy::class); + } + + /** + * @covers ::createShareSession + * @covers ::__construct + */ + public function testShouldCreateShareSession() + { + $shareSessionRequest = (new ShareSessionRequestBuilder()) + ->withPolicy($this->policyMock) + ->withRedirectUri(self::URI) + ->withExtension($this->extensionMock) + ->build(); + + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'some_id', + 'status' => 'some_status', + 'expiry' => 'some_time', + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $identityService = $this->createMock(IdentityService::class); + + $result = $identityService->createShareSession($shareSessionRequest); + + $this->assertInstanceOf(ShareSessionCreated::class, $result); + } + + /** + * @covers ::createShareQrCode + * @covers ::__construct + */ + public function testShouldCreateShareQrCode() + { + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'some_id', + 'uri' => 'some_uri', + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $identityService = $this->createMock(IdentityService::class); + + $result = $identityService->createShareQrCode(TestData::SOME_ID); + + $this->assertInstanceOf(ShareSessionCreatedQrCode::class, $result); + } + + /** + * @covers ::fetchShareQrCode + * @covers ::__construct + */ + public function testShouldFetchShareQrCode() + { + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'id', + 'expiry' => 'expiry', + 'policy' => 'policy', + 'extensions' => [['type' => 'type', 'content' => 'content']], + 'session' => ['id' => 'id', 'status' => 'status', 'expiry' => 'expiry'], + 'redirectUri' => 'redirectUri', + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $identityService = $this->createMock(IdentityService::class); + + $result = $identityService->fetchShareQrCode(TestData::SOME_ID); + + $this->assertInstanceOf(ShareSessionFetchedQrCode::class, $result); + } + + /** + * @covers ::fetchShareSession + * @covers ::__construct + */ + public function testShouldFetchShareSession() + { + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'SOME_ID', + 'status' => 'SOME_STATUS', + 'expiry' => 'SOME_EXPIRY', + 'created' => 'SOME_CREATED', + 'updated' => 'SOME_UPDATED', + 'qrCode' => ['id' => 'SOME_QRCODE_ID'], + 'receipt' => ['id' => 'SOME_RECEIPT_ID'], + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $identityService = $this->createMock(IdentityService::class); + + $result = $identityService->fetchShareSession(TestData::SOME_ID); + + $this->assertInstanceOf(ShareSessionFetched::class, $result); + } +} diff --git a/tests/Identity/Policy/PolicyBuilderTest.php b/tests/Identity/Policy/PolicyBuilderTest.php new file mode 100644 index 00000000..d223bd79 --- /dev/null +++ b/tests/Identity/Policy/PolicyBuilderTest.php @@ -0,0 +1,644 @@ +withFamilyName() + ->withGivenNames() + ->withFullName() + ->withDateOfBirth() + ->withGender() + ->withPostalAddress() + ->withStructuredPostalAddress() + ->withNationality() + ->withPhoneNumber() + ->withSelfie() + ->withEmail() + ->withDocumentDetails() + ->withDocumentImages() + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + ['name' => 'family_name', 'optional' => false], + ['name' => 'given_names', 'optional' => false], + ['name' => 'full_name', 'optional' => false], + ['name' => 'date_of_birth', 'optional' => false], + ['name' => 'gender', 'optional' => false], + ['name' => 'postal_address', 'optional' => false], + ['name' => 'structured_postal_address', 'optional' => false], + ['name' => 'nationality', 'optional' => false], + ['name' => 'phone_number', 'optional' => false], + ['name' => 'selfie', 'optional' => false], + ['name' => 'email_address', 'optional' => false], + ['name' => 'document_details', 'optional' => false], + ['name' => 'document_images', 'optional' => false], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withWantedAttributeByName + */ + public function testWithWantedAttributeByNameWithConstraints() + { + $someAttributeName = 'some_attribute_name'; + $sourceConstraint = (new SourceConstraintBuilder()) + ->withWantedAnchor(new WantedAnchor('SOME')) + ->build(); + + $constraints = [ + $sourceConstraint, + ]; + + $policy = (new PolicyBuilder()) + ->withWantedAttributeByName($someAttributeName, $constraints, true) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + [ + 'name' => $someAttributeName, + 'optional' => false, + "constraints" => [ + [ + "type" => "SOURCE", + "preferred_sources" => [ + "anchors" => [ + [ + "name" => "SOME", + "sub_type" => "", + ] + ], + "soft_preference" => false, + ], + ], + ], + "accept_self_asserted" => true, + ], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertJsonStringEqualsJsonString( + json_encode($expectedWantedAttributeData), + json_encode($policy) + ); + } + + /** + * @covers ::withWantedAttribute + * @covers ::withFamilyName + */ + public function testWithDuplicateAttribute() + { + $policy = (new PolicyBuilder()) + ->withFamilyName() + ->withFamilyName() + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + ['name' => 'family_name', 'optional' => false], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withWantedAttribute + * @covers ::withFamilyName + */ + public function testWithDuplicateAttributeDifferentConstraints() + { + $sourceConstraint = (new SourceConstraintBuilder()) + ->withWantedAnchor(new WantedAnchor('SOME')) + ->build(); + + $sourceConstraint2 = (new SourceConstraintBuilder()) + ->withWantedAnchor(new WantedAnchor('SOME_2')) + ->build(); + + + $policy = (new PolicyBuilder()) + ->withFamilyName() + ->withFamilyName([$sourceConstraint]) + ->withFamilyName([$sourceConstraint2]) + ->build(); + + $jsonData = $policy->jsonSerialize(); + + $this->assertCount(3, $jsonData->wanted); + foreach ($jsonData->wanted as $wantedAttribute) { + $this->assertEquals('family_name', $wantedAttribute->getName()); + } + } + + /** + * @covers ::build + * @covers ::withWantedAttributeByName + */ + public function testWithWantedAttributeByName() + { + $policy = (new PolicyBuilder()) + ->withWantedAttributeByName('family_name') + ->withWantedAttributeByName('given_names') + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + ['name' => 'family_name', 'optional' => false], + ['name' => 'given_names', 'optional' => false], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::build + * @covers ::withWantedAttribute + */ + public function testWithAttributeObjects() + { + $wantedFamilyName = (new WantedAttributeBuilder()) + ->withName('family_name') + ->build(); + + $wantedGivenNames = (new WantedAttributeBuilder()) + ->withName('given_names') + ->build(); + + $policy = (new PolicyBuilder()) + ->withWantedAttribute($wantedFamilyName) + ->withWantedAttribute($wantedGivenNames) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + ['name' => 'family_name', 'optional' => false], + ['name' => 'given_names', 'optional' => false], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withDateOfBirth + * @covers ::withAgeOver + * @covers ::withAgeUnder + * @covers ::withAgeDerivedAttribute + */ + public function testWithAgeDerivedAttributes() + { + $policy = (new PolicyBuilder()) + ->withDateOfBirth() + ->withAgeOver(18) + ->withAgeUnder(30) + ->withAgeUnder(40) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + ['name' => 'date_of_birth', 'optional' => false], + ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_over:18'], + ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_under:30'], + ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_under:40'], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withAgeDerivedAttribute + */ + public function testWithAgeDerivedAttributesWithConstraints() + { + $sourceConstraint = (new SourceConstraintBuilder()) + ->withWantedAnchor(new WantedAnchor('SOME')) + ->build(); + + + $policy = (new PolicyBuilder()) + ->withAgeDerivedAttribute(UserProfile::AGE_OVER . '18', [$sourceConstraint]) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + [ + 'name' => 'date_of_birth', + 'optional' => false, + 'derivation' => 'age_over:18', + "constraints" => [ + [ + "type" => "SOURCE", + "preferred_sources" => [ + "anchors" => [ + [ + "name" => "SOME", + "sub_type" => "", + ] + ], + "soft_preference" => false, + ], + ], + ], + ], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertJsonStringEqualsJsonString( + json_encode($expectedWantedAttributeData), + json_encode($policy) + ); + } + + + /** + * @covers ::withAgeUnder + * @covers ::withAgeDerivedAttribute + * @covers ::withWantedAttribute + */ + public function testWithDuplicateAgeDerivedAttributes() + { + $policy = (new PolicyBuilder()) + ->withAgeUnder(30) + ->withAgeUnder(30) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [ + ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_under:30'], + ], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + * @covers ::withPinAuthentication + * @covers ::withWantedAuthType + */ + public function testWithAuthTypes() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication() + ->withPinAuthentication() + ->withWantedAuthType(99) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE, 99], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + * @covers ::withPinAuthentication + * @covers ::withWantedAuthType + */ + public function testWithAuthTypesTrue() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication() + ->withPinAuthentication() + ->withWantedAuthType(99) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE, 99], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + * @covers ::withPinAuthentication + * @covers ::withWantedAuthType + */ + public function testWithAuthTypesFalse() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication(false) + ->withPinAuthentication(false) + ->withWantedAuthType(99, false) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + * @covers ::withPinAuthentication + */ + public function testWithAuthEnabledThenDisabled() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication() + ->withSelfieAuthentication(false) + ->withPinAuthentication() + ->withPinAuthentication(false) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + */ + public function testWithSameAuthTypeAddedOnlyOnce() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication() + ->withSelfieAuthentication() + ->withSelfieAuthentication() + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + */ + public function testWithOnlyTwoAuthTypes() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication() + ->withPinAuthentication() + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + */ + public function testWithNoSelfieAuthAfterRemoval() + { + $policy = (new PolicyBuilder()) + ->withSelfieAuthentication() + ->withSelfieAuthentication(false) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withSelfieAuthentication + */ + public function testWithNoPinAuthAfterRemoval() + { + $policy = (new PolicyBuilder()) + ->withPinAuthentication() + ->withPinAuthentication(false) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + + /** + * @covers ::withWantedRememberMe + */ + public function testWithRememberMe() + { + $policy = (new PolicyBuilder()) + ->withWantedRememberMe(true) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => true, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withWantedRememberMe + */ + public function testWithoutRememberMe() + { + $policy = (new PolicyBuilder()) + ->withWantedRememberMe(false) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withWantedRememberMeOptional + */ + public function testWithRememberMeOptional() + { + $policy = (new PolicyBuilder()) + ->withWantedRememberMeOptional(true) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => true, + 'identity_profile_requirements' => null, + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withWantedRememberMeOptional + */ + public function testWithoutRememberMeOptional() + { + $policy = (new PolicyBuilder()) + ->withWantedRememberMeOptional(false) + ->build(); + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null + ]; + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + } + + /** + * @covers ::withIdentityProfileRequirements + * @covers \Yoti\Identity\Policy\Policy::__construct + * @covers \Yoti\Identity\Policy\Policy::getIdentityProfileRequirements + * @covers \Yoti\Identity\Policy\Policy::jsonSerialize + */ + public function testWithIdentityProfileRequirements() + { + $identityProfileSample = (object)[ + 'trust_framework' => 'UK_TFIDA', + 'scheme' => [ + 'type' => 'DBS', + 'objective' => 'STANDARD' + ] + ]; + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => $identityProfileSample + ]; + + $policy = (new PolicyBuilder()) + ->withIdentityProfileRequirements($identityProfileSample) + ->build(); + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + $this->assertEquals($identityProfileSample, $policy->getIdentityProfileRequirements()); + } +} diff --git a/tests/Identity/Policy/WantedAnchorBuilderTest.php b/tests/Identity/Policy/WantedAnchorBuilderTest.php new file mode 100644 index 00000000..2d0479e0 --- /dev/null +++ b/tests/Identity/Policy/WantedAnchorBuilderTest.php @@ -0,0 +1,39 @@ +withValue($someName) + ->withSubType($someSubType) + ->build(); + + $expectedJsonData = [ + 'name' => $someName, + 'sub_type' => $someSubType, + ]; + + $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAnchor)); + } +} diff --git a/tests/Identity/Policy/WantedAttributeBuilderTest.php b/tests/Identity/Policy/WantedAttributeBuilderTest.php new file mode 100644 index 00000000..7cd8a8f1 --- /dev/null +++ b/tests/Identity/Policy/WantedAttributeBuilderTest.php @@ -0,0 +1,162 @@ +withWantedAnchor(new WantedAnchor('SOME')) + ->build(); + + $wantedAttribute = (new WantedAttributeBuilder()) + ->withName($someName) + ->withDerivation($someDerivation) + ->withOptional(true) + ->withConstraint($sourceConstraint) + ->withAcceptSelfAsserted(false) + ->build(); + + $expectedJsonData = [ + 'name' => $someName, + 'optional' => true, + 'derivation' => $someDerivation, + 'constraints' => [$sourceConstraint], + 'accept_self_asserted' => false, + ]; + + $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttribute)); + $this->assertTrue($wantedAttribute->getOptional()); + $this->assertContains($sourceConstraint, $wantedAttribute->getConstraints()); + $this->assertFalse($wantedAttribute->getAcceptSelfAsserted()); + } + + /** + * @covers ::build + * @covers ::withName + */ + public function testEmptyName() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('name cannot be empty'); + + (new WantedAttributeBuilder()) + ->withName('') + ->build(); + } + + /** + * @covers ::withAcceptSelfAsserted + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::__construct + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::jsonSerialize + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::getAcceptSelfAsserted + */ + public function testAcceptSelfAsserted() + { + $someName = 'some name'; + + $expectedJsonData = [ + 'name' => $someName, + 'optional' => false, + 'accept_self_asserted' => true, + ]; + + $wantedAttributeDefault = (new WantedAttributeBuilder()) + ->withName($someName) + ->withAcceptSelfAsserted(true) + ->build(); + + $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttributeDefault)); + + $wantedAttribute = (new WantedAttributeBuilder()) + ->withName($someName) + ->withAcceptSelfAsserted(true) + ->build(); + + $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttribute)); + } + + /** + * @covers ::withAcceptSelfAsserted + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::__construct + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::jsonSerialize + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::getAcceptSelfAsserted + */ + public function testWithoutAcceptSelfAsserted() + { + $someName = 'some name'; + + $expectedJsonData = [ + 'name' => $someName, + 'optional' => false, + 'accept_self_asserted' => false, + ]; + + $wantedAttribute = (new WantedAttributeBuilder()) + ->withName($someName) + ->withAcceptSelfAsserted(false) + ->build(); + + $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttribute)); + } + + /** + * @covers ::withAcceptSelfAsserted + * @covers ::withConstraints + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::__construct + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::jsonSerialize + * @covers \Yoti\ShareUrl\Policy\WantedAttribute::getAcceptSelfAsserted + */ + public function testWithMultipleConstraints() + { + $sourceConstraint = (new SourceConstraintBuilder()) + ->withWantedAnchor(new WantedAnchor('SOME')) + ->build(); + + $sourceConstraint2 = (new SourceConstraintBuilder()) + ->withWantedAnchor(new WantedAnchor('SOME_2')) + ->build(); + + + $constraints = [ + $sourceConstraint, + $sourceConstraint2 + ]; + + $wantedAttribute = (new WantedAttributeBuilder()) + ->withName('someName') + ->withAcceptSelfAsserted(false) + ->withConstraints($constraints) + ->build(); + + $this->assertEquals($constraints, $wantedAttribute->getConstraints()); + } +} diff --git a/tests/Identity/ShareSessionCreatedQrCodeTest.php b/tests/Identity/ShareSessionCreatedQrCodeTest.php new file mode 100644 index 00000000..c0fc50ba --- /dev/null +++ b/tests/Identity/ShareSessionCreatedQrCodeTest.php @@ -0,0 +1,42 @@ + self::SOME_ID, + 'uri' => self::SOME_URI, + 'failed' => 'failed' + ]); + + $expected = [ + 'id' => self::SOME_ID, + 'uri' => self::SOME_URI, + ]; + + $this->assertInstanceOf(ShareSessionCreatedQrCode::class, $qrCode); + + $this->assertEquals(self::SOME_ID, $qrCode->getId()); + $this->assertEquals(self::SOME_URI, $qrCode->getUri()); + + $this->assertEquals(json_encode($expected), json_encode($qrCode)); + } +} diff --git a/tests/Identity/ShareSessionCreatedTest.php b/tests/Identity/ShareSessionCreatedTest.php new file mode 100644 index 00000000..380be268 --- /dev/null +++ b/tests/Identity/ShareSessionCreatedTest.php @@ -0,0 +1,45 @@ + self::SOME_ID, + 'status' => self::SOME_STATUS, + 'expiry' => self::SOME_EXPIRY, + 'failed' => 'SQL injection' + ]); + + $expected = [ + 'id' => self::SOME_ID, + 'status' => self::SOME_STATUS, + 'expiry' => self::SOME_EXPIRY, + ]; + + $this->assertInstanceOf(ShareSessionCreated::class, $shareSession); + $this->assertEquals(self::SOME_ID, $shareSession->getId()); + $this->assertEquals(self::SOME_STATUS, $shareSession->getStatus()); + $this->assertEquals(self::SOME_EXPIRY, $shareSession->getExpiry()); + $this->assertEquals(json_encode($expected), json_encode($shareSession)); + } +} diff --git a/tests/Identity/ShareSessionFetchedQrCodeTest.php b/tests/Identity/ShareSessionFetchedQrCodeTest.php new file mode 100644 index 00000000..3be47c69 --- /dev/null +++ b/tests/Identity/ShareSessionFetchedQrCodeTest.php @@ -0,0 +1,76 @@ + 'some', 'content' => 'content'], + ['type' => 'some2', 'content' => 'content2'], + ]; + + $shareSession = [ + 'id' => 'some', + 'status' => 'status', + 'expiry' => 'expiry', + ]; + + $qrCode = new ShareSessionFetchedQrCode([ + 'id' => self::SOME_ID, + 'expiry' => self::SOME_EXPIRY, + 'policy' => self::SOME_POLICY, + 'extensions' => $extensions, + 'session' => $shareSession, + 'redirectUri' => self::SOME_REDIRECT_URI, + ]); + + $expected = [ + 'id' => self::SOME_ID, + 'expiry' => self::SOME_EXPIRY, + 'policy' => self::SOME_POLICY, + 'extensions' => $extensions, + 'session' => $shareSession, + 'redirectUri' => self::SOME_REDIRECT_URI, + ]; + + $this->assertInstanceOf(ShareSessionFetchedQrCode::class, $qrCode); + + $this->assertEquals(self::SOME_ID, $qrCode->getId()); + $this->assertEquals(self::SOME_EXPIRY, $qrCode->getExpiry()); + $this->assertEquals(self::SOME_POLICY, $qrCode->getPolicy()); + $this->assertEquals(self::SOME_REDIRECT_URI, $qrCode->getRedirectUri()); + + $this->assertInstanceOf(ShareSessionCreated::class, $qrCode->getSession()); + + $this->assertContainsOnlyInstancesOf(Extension::class, $qrCode->getExtensions()); + + $this->assertEquals(self::SOME_REDIRECT_URI, $qrCode->getRedirectUri()); + + $this->assertEquals(json_encode($expected), json_encode($qrCode)); + } +} diff --git a/tests/Identity/ShareSessionFetchedTest.php b/tests/Identity/ShareSessionFetchedTest.php new file mode 100644 index 00000000..cc38224d --- /dev/null +++ b/tests/Identity/ShareSessionFetchedTest.php @@ -0,0 +1,66 @@ + self::SOME_ID, + 'status' => self::SOME_STATUS, + 'expiry' => self::SOME_EXPIRY, + 'created' => self::SOME_CREATED, + 'updated' => self::SOME_UPDATED, + 'failed' => 'SQL injection', + 'qrCode' => ['id' => self::SOME_QRCODE_ID], + 'receipt' => ['id' => self::SOME_RECEIPT_ID], + ]); + + $expected = [ + 'id' => self::SOME_ID, + 'status' => self::SOME_STATUS, + 'expiry' => self::SOME_EXPIRY, + 'created' => self::SOME_CREATED, + 'updated' => self::SOME_UPDATED, + 'qrCodeId' => self::SOME_QRCODE_ID, + 'receiptId' => self::SOME_RECEIPT_ID, + ]; + + $this->assertInstanceOf(ShareSessionFetched::class, $shareSession); + $this->assertEquals(self::SOME_ID, $shareSession->getId()); + $this->assertEquals(self::SOME_STATUS, $shareSession->getStatus()); + $this->assertEquals(self::SOME_EXPIRY, $shareSession->getExpiry()); + $this->assertEquals(self::SOME_CREATED, $shareSession->getCreated()); + $this->assertEquals(self::SOME_UPDATED, $shareSession->getUpdated()); + $this->assertEquals(self::SOME_QRCODE_ID, $shareSession->getQrCodeId()); + $this->assertEquals(self::SOME_RECEIPT_ID, $shareSession->getReceiptId()); + $this->assertEquals(json_encode($expected), json_encode($shareSession)); + } +} diff --git a/tests/Identity/ShareSessionNotificationBuilderTest.php b/tests/Identity/ShareSessionNotificationBuilderTest.php new file mode 100644 index 00000000..ffee1e5e --- /dev/null +++ b/tests/Identity/ShareSessionNotificationBuilderTest.php @@ -0,0 +1,80 @@ + 'auth', 'header_3' => 'auth_3']; + + /** + * @covers ::withUrl + * @covers ::withMethod + * @covers ::withHeader + * @covers ::withVerifyTls + * @covers ::build + * @covers \Yoti\Identity\ShareSessionNotification::getUrl + * @covers \Yoti\Identity\ShareSessionNotification::getHeaders + * @covers \Yoti\Identity\ShareSessionNotification::getMethod + * @covers \Yoti\Identity\ShareSessionNotification::getUrl + * @covers \Yoti\Identity\ShareSessionNotification::__construct + */ + public function testShouldBuildCorrectly() + { + $shareNotification = (new ShareSessionNotificationBuilder()) + ->withMethod() + ->withUrl(self::URL) + ->withHeader(self::HEADER_KEY, self::HEADER_VALUE) + ->withVerifyTls() + ->build(); + + $this->assertInstanceOf(ShareSessionNotification::class, $shareNotification); + + $this->assertEquals(self::URL, $shareNotification->getUrl()); + $this->assertEquals([self::HEADER_KEY => self::HEADER_VALUE], $shareNotification->getHeaders()); + $this->assertEquals('POST', $shareNotification->getMethod()); + } + + /** + * @covers ::withUrl + * @covers ::withMethod + * @covers ::withHeaders + * @covers ::withVerifyTls + * @covers ::build + * @covers \Yoti\Identity\ShareSessionNotification::getHeaders + * @covers \Yoti\Identity\ShareSessionNotification::isVerifyTls + * @covers \Yoti\Identity\ShareSessionNotification::jsonSerialize + * @covers \Yoti\Identity\ShareSessionNotification::__construct + */ + public function testShouldBuildCorrectlyWithMultipleHeaders() + { + $shareNotification = (new ShareSessionNotificationBuilder()) + ->withMethod() + ->withUrl(self::URL) + ->withHeaders(self::HEADERS) + ->withVerifyTls(false) + ->build(); + + $expected = [ + 'url' => self::URL, + 'method' => 'POST', + 'verifyTls' => false, + 'headers' => self::HEADERS, + ]; + + $this->assertEquals(self::HEADERS, $shareNotification->getHeaders()); + $this->assertFalse($shareNotification->isVerifyTls()); + $this->assertEquals(json_encode($expected), json_encode($shareNotification)); + } +} diff --git a/tests/Identity/ShareSessionRequestBuilderTest.php b/tests/Identity/ShareSessionRequestBuilderTest.php new file mode 100644 index 00000000..4be3a1ef --- /dev/null +++ b/tests/Identity/ShareSessionRequestBuilderTest.php @@ -0,0 +1,100 @@ +extensionMock = $this->createMock(Extension::class); + $this->policyMock = $this->createMock(Policy::class); + } + + /** + * @covers ::withRedirectUri + * @covers ::withPolicy + * @covers ::withExtension + * @covers ::withNotification + * @covers ::withSubject + * @covers ::build + * @covers \Yoti\Identity\ShareSessionRequest::getPolicy + * @covers \Yoti\Identity\ShareSessionRequest::getNotification + * @covers \Yoti\Identity\ShareSessionRequest::getExtensions + * @covers \Yoti\Identity\ShareSessionRequest::getSubject + * @covers \Yoti\Identity\ShareSessionRequest::__construct + */ + public function testShouldBuildCorrectly() + { + $subject = [ + 'key' => (object)['some' => 'good'] + ]; + + $shareNotification = (new ShareSessionNotificationBuilder()) + ->withMethod() + ->withUrl('some') + ->withHeader('some', 'some') + ->withVerifyTls() + ->build(); + + $shareRequest = (new ShareSessionRequestBuilder()) + ->withSubject($subject) + ->withNotification($shareNotification) + ->withPolicy($this->policyMock) + ->withRedirectUri(self::URI) + ->withExtension($this->extensionMock) + ->build(); + + $this->assertInstanceOf(ShareSessionRequest::class, $shareRequest); + + $this->assertEquals($subject, $shareRequest->getSubject()); + $this->assertEquals([$this->extensionMock], $shareRequest->getExtensions()); + $this->assertEquals($this->policyMock, $shareRequest->getPolicy()); + $this->assertEquals($shareNotification, $shareRequest->getNotification()); + $this->assertEquals(self::URI, $shareRequest->getRedirectUri()); + } + + /** + * @covers ::withRedirectUri + * @covers ::withPolicy + * @covers ::withExtensions + * @covers ::withNotification + * @covers ::withSubject + * @covers ::build + * @covers \Yoti\Identity\ShareSessionRequest::getExtensions + * @covers \Yoti\Identity\ShareSessionRequest::__construct + * @covers \Yoti\Identity\ShareSessionRequest::jsonSerialize + */ + public function testShouldBuildCorrectlyWithMultipleExtensions() + { + $shareRequest = (new ShareSessionRequestBuilder()) + ->withPolicy($this->policyMock) + ->withRedirectUri(self::URI) + ->withExtensions([$this->extensionMock]) + ->build(); + + + $expected = [ + 'policy' => $this->policyMock, + 'redirectUri' => self::URI, + 'extensions' => [$this->extensionMock], + ]; + + $this->assertEquals([$this->extensionMock], $shareRequest->getExtensions()); + $this->assertEquals(json_encode($expected), json_encode($shareRequest)); + } +} diff --git a/tests/YotiClientTest.php b/tests/YotiClientTest.php index 24ddaa36..828373ab 100755 --- a/tests/YotiClientTest.php +++ b/tests/YotiClientTest.php @@ -13,6 +13,12 @@ use Yoti\Aml\Profile as AmlProfile; use Yoti\Aml\Result as AmlResult; use Yoti\Exception\DateTimeException; +use Yoti\Identity\Policy\Policy; +use Yoti\Identity\ShareSessionCreated; +use Yoti\Identity\ShareSessionCreatedQrCode; +use Yoti\Identity\ShareSessionFetched; +use Yoti\Identity\ShareSessionFetchedQrCode; +use Yoti\Identity\ShareSessionRequestBuilder; use Yoti\Profile\ActivityDetails; use Yoti\ShareUrl\DynamicScenarioBuilder; use Yoti\ShareUrl\Policy\DynamicPolicyBuilder; @@ -204,6 +210,140 @@ public function testCreateShareUrl() $this->assertInstanceOf(ShareUrlResult::class, $result); } + /** + * @covers ::createShareSession + * @covers ::__construct + */ + public function testCreateShareSession() + { + $policy = $this->createMock(Policy::class); + $redirectUri = 'https://host/redirect/'; + + $shareSessionRequest = (new ShareSessionRequestBuilder()) + ->withPolicy($policy) + ->withRedirectUri($redirectUri) + ->build(); + + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'some_id', + 'status' => 'some_status', + 'expiry' => 'some_time', + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $httpClient = $this->createMock(ClientInterface::class); + $httpClient + ->expects($this->once()) + ->method('sendRequest') + ->willReturn($response); + + $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ + Config::HTTP_CLIENT => $httpClient, + ]); + + $result = $yotiClient->createShareSession($shareSessionRequest); + + $this->assertInstanceOf(ShareSessionCreated::class, $result); + } + + /** + * @covers ::createShareQrCode + * @covers ::__construct + */ + public function testCreateShareQrCode() + { + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'some_id', + 'uri' => 'some_uri', + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $httpClient = $this->createMock(ClientInterface::class); + $httpClient + ->expects($this->once()) + ->method('sendRequest') + ->willReturn($response); + + $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ + Config::HTTP_CLIENT => $httpClient, + ]); + + $result = $yotiClient->createShareQrCode(TestData::SOME_ID); + + $this->assertInstanceOf(ShareSessionCreatedQrCode::class, $result); + } + + /** + * @covers ::fetchShareQrCode + * @covers ::__construct + */ + public function testFetchShareQrCode() + { + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'id', + 'expiry' => 'expiry', + 'policy' => 'policy', + 'extensions' => [['type' => 'type', 'content' => 'content']], + 'session' => ['id' => 'id', 'status' => 'status', 'expiry' => 'expiry'], + 'redirectUri' => 'redirectUri', + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $httpClient = $this->createMock(ClientInterface::class); + $httpClient + ->expects($this->once()) + ->method('sendRequest') + ->willReturn($response); + + $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ + Config::HTTP_CLIENT => $httpClient, + ]); + + $result = $yotiClient->fetchShareQrCode(TestData::SOME_ID); + + $this->assertInstanceOf(ShareSessionFetchedQrCode::class, $result); + } + + /** + * @covers ::fetchShareSession + * @covers ::__construct + */ + public function testFetchShareSession() + { + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ + 'id' => 'SOME_ID', + 'status' => 'SOME_STATUS', + 'expiry' => 'SOME_EXPIRY', + 'created' => 'SOME_CREATED', + 'updated' => 'SOME_UPDATED', + 'qrCode' => ['id' => 'SOME_QRCODE_ID'], + 'receipt' => ['id' => 'SOME_RECEIPT_ID'], + ]))); + + $response->method('getStatusCode')->willReturn(201); + + $httpClient = $this->createMock(ClientInterface::class); + $httpClient + ->expects($this->once()) + ->method('sendRequest') + ->willReturn($response); + + $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ + Config::HTTP_CLIENT => $httpClient, + ]); + + $result = $yotiClient->fetchShareSession(TestData::SOME_ID); + + $this->assertInstanceOf(ShareSessionFetched::class, $result); + } + /** * @covers ::getLoginUrl */ From d0e0ea342d110f0fccf61a47724f9b08fb399bc4 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Thu, 29 Jun 2023 14:19:10 +0100 Subject: [PATCH 04/19] SDK-2335:Added expanded document fields media feature --- .../resources/views/success.blade.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/examples/doc-scan/resources/views/success.blade.php b/examples/doc-scan/resources/views/success.blade.php index c2944a0d..0e49c218 100644 --- a/examples/doc-scan/resources/views/success.blade.php +++ b/examples/doc-scan/resources/views/success.blade.php @@ -346,6 +346,41 @@ class="badge badge-primary">{{ $document->getIssuingCountry() }} @endif + @if ($document->getExpandedDocumentFields()) +
+
+

+ +

+
+
+
+ @if ($document->getExpandedDocumentFields()->getMedia()) +
Media
+ + + + + + + +
ID + + {{ $document->getExpandedDocumentFields()->getMedia()->getId() }} + +
+ @endif +
+
+
+ @endif + @if ($document->getDocumentIdPhoto())
From 6510b92ba8b97e07125cdf4dc9f42a4602bfd1c6 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 30 Jun 2023 10:35:12 +0100 Subject: [PATCH 05/19] SDK-2236: added enabling expanded document fields feature --- .../app/Http/Controllers/HomeController.php | 2 ++ .../RequestedTextExtractionTaskBuilder.php | 20 +++++++++++- .../RequestedTextExtractionTaskConfig.php | 18 ++++++++++- .../ExpandedDocumentFieldsResponse.php | 32 +++++++++++++++++++ .../Retrieve/IdDocumentResourceResponse.php | 17 ++++++++++ 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 src/DocScan/Session/Retrieve/ExpandedDocumentFieldsResponse.php diff --git a/examples/doc-scan/app/Http/Controllers/HomeController.php b/examples/doc-scan/app/Http/Controllers/HomeController.php index 5aae0ea8..6f75236a 100644 --- a/examples/doc-scan/app/Http/Controllers/HomeController.php +++ b/examples/doc-scan/app/Http/Controllers/HomeController.php @@ -118,6 +118,7 @@ public function show(Request $request, DocScanClient $client) (new RequestedTextExtractionTaskBuilder()) ->withManualCheckAlways() ->withChipDataDesired() + ->withCreateExpandedDocumentFields(true) ->build() ) ->withRequestedTask( @@ -160,6 +161,7 @@ public function show(Request $request, DocScanClient $client) ) ->build(); + $session = $client->createSession($sessionSpec); $request->session()->put('YOTI_SESSION_ID', $session->getSessionId()); diff --git a/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskBuilder.php b/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskBuilder.php index 5b29fca1..174828f9 100644 --- a/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskBuilder.php +++ b/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskBuilder.php @@ -58,6 +58,23 @@ public function withManualCheck(string $manualCheck): self return $this->setManualCheck($manualCheck); } + /** + * @var bool + */ + private $createExpandedDocumentFields; + + /** + * + * @param string $createExpandedDocumentFields + * + * @return $this + */ + public function withCreateExpandedDocumentFields(bool $createExpandedDocumentFields): self + { + $this->createExpandedDocumentFields = $createExpandedDocumentFields; + return $this; + } + /** * @return RequestedTextExtractionTask */ @@ -65,7 +82,8 @@ public function build(): RequestedTextExtractionTask { Validation::notEmptyString($this->manualCheck, 'manualCheck'); - $config = new RequestedTextExtractionTaskConfig($this->manualCheck, $this->chipData); + $config = new RequestedTextExtractionTaskConfig($this->manualCheck, $this->chipData, + $this->createExpandedDocumentFields); return new RequestedTextExtractionTask($config); } } diff --git a/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfig.php b/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfig.php index 9a9fb083..7e5716d1 100644 --- a/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfig.php +++ b/src/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfig.php @@ -19,14 +19,21 @@ class RequestedTextExtractionTaskConfig implements RequestedTaskConfigInterface */ private $chipData; + /** + * @var bool|null + */ + private $createExpandedDocumentFields; + /** * @param string $manualCheck * @param string|null $chipData + * @param bool|null $createExpandedDocumentFields */ - public function __construct(string $manualCheck, ?string $chipData = null) + public function __construct(string $manualCheck, ?string $chipData = null, ?bool $createExpandedDocumentFields = false) { $this->manualCheck = $manualCheck; $this->chipData = $chipData; + $this->createExpandedDocumentFields = $createExpandedDocumentFields; } /** @@ -37,6 +44,7 @@ public function jsonSerialize(): stdClass return (object)Json::withoutNullValues([ 'manual_check' => $this->getManualCheck(), 'chip_data' => $this->getChipData(), + 'create_expanded_document_fields' => $this->getCreateExpandedDocumentFields(), ]); } @@ -55,4 +63,12 @@ public function getChipData(): ?string { return $this->chipData; } + + /** + * @return bool + */ + public function getCreateExpandedDocumentFields(): ?bool + { + return $this->createExpandedDocumentFields; + } } diff --git a/src/DocScan/Session/Retrieve/ExpandedDocumentFieldsResponse.php b/src/DocScan/Session/Retrieve/ExpandedDocumentFieldsResponse.php new file mode 100644 index 00000000..acf17f74 --- /dev/null +++ b/src/DocScan/Session/Retrieve/ExpandedDocumentFieldsResponse.php @@ -0,0 +1,32 @@ + $documentFields + */ + public function __construct(array $documentFields) + { + $this->media = isset($documentFields['media']) + ? new MediaResponse($documentFields['media']) + : null; + } + + /** + * @return MediaResponse|null + */ + public function getMedia(): ?MediaResponse + { + return $this->media; + } +} diff --git a/src/DocScan/Session/Retrieve/IdDocumentResourceResponse.php b/src/DocScan/Session/Retrieve/IdDocumentResourceResponse.php index b6e7f46a..6d9dc824 100644 --- a/src/DocScan/Session/Retrieve/IdDocumentResourceResponse.php +++ b/src/DocScan/Session/Retrieve/IdDocumentResourceResponse.php @@ -24,6 +24,11 @@ class IdDocumentResourceResponse extends ResourceResponse */ private $documentFields; + /** + * @var ExpandedDocumentFieldsResponse|null + */ + private $expandedDocumentFields; + /** * @var DocumentIdPhotoResponse|null */ @@ -49,6 +54,10 @@ public function __construct(array $idDocument) $this->documentFields = isset($idDocument['document_fields']) ? new DocumentFieldsResponse($idDocument['document_fields']) : null; + + $this->expandedDocumentFields = isset($idDocument['expanded_document_fields']) + ? new ExpandedDocumentFieldsResponse($idDocument['expanded_document_fields']) + : null; $this->documentIdPhoto = isset($idDocument['document_id_photo']) ? new DocumentIdPhotoResponse($idDocument['document_id_photo']) @@ -87,6 +96,14 @@ public function getDocumentFields(): ?DocumentFieldsResponse return $this->documentFields; } + /** + * @return ExpandedDocumentFieldsResponse|null + */ + public function getExpandedDocumentFields(): ?ExpandedDocumentFieldsResponse + { + return $this->expandedDocumentFields; + } + /** * @return DocumentIdPhotoResponse|null */ From 51c1dc79a3f0f68f72154eabef39636ed54ca646 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 07:53:50 +0100 Subject: [PATCH 06/19] SDK-2336:Update tests --- .../RequestedSupplementaryDocTextExtractionTaskConfigTest.php | 2 ++ .../Create/Task/RequestedTextExtractionTaskConfigTest.php | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php index 4d0b0f76..94cc80ba 100644 --- a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php @@ -11,6 +11,7 @@ class RequestedSupplementaryDocTextExtractionTaskConfigTest extends TestCase { private const SOME_MANUAL_CHECK = 'someManualCheck'; + private const SOME_EXPANDED_DOCUMENT_FIELDS = 'false'; /** * @test @@ -24,6 +25,7 @@ public function shouldSerializeToJsonCorrectlyWithRequiredProperties() $expected = [ 'manual_check' => self::SOME_MANUAL_CHECK, + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); diff --git a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php index 630b5652..2aefd55c 100644 --- a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php @@ -12,6 +12,8 @@ class RequestedTextExtractionTaskConfigTest extends TestCase { private const SOME_MANUAL_CHECK = 'someManualCheck'; private const SOME_CHIP_DATA = 'someChipData'; + private const SOME_EXPANDED_DOCUMENT_FIELDS = 'false'; + /** * @test @@ -44,6 +46,7 @@ public function shouldSerializeToJsonCorrectlyWithAllProperties() $expected = [ 'manual_check' => self::SOME_MANUAL_CHECK, 'chip_data' => self::SOME_CHIP_DATA, + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); From 5f15bca43bf76e11a9f2d83712519d9dc73e29ad Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 07:56:25 +0100 Subject: [PATCH 07/19] SDK-2336:Update tests --- ...RequestedSupplementaryDocTextExtractionTaskConfigTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php index 94cc80ba..7023785e 100644 --- a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php @@ -24,8 +24,9 @@ public function shouldSerializeToJsonCorrectlyWithRequiredProperties() $result = new RequestedSupplementaryDocTextExtractionTaskConfig(self::SOME_MANUAL_CHECK); $expected = [ - 'manual_check' => self::SOME_MANUAL_CHECK, - 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, + 'manual_check' => self::SOME_MANUAL_CHECK + ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); From cc63af3952af1d1c6daf2d5e21bec5b272048729 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 08:01:08 +0100 Subject: [PATCH 08/19] SDK-2336:Update tests --- .../Create/Task/RequestedTextExtractionTaskConfigTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php index 2aefd55c..e9920f82 100644 --- a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php @@ -26,6 +26,7 @@ public function shouldSerializeToJsonCorrectlyWithRequiredProperties() $result = new RequestedTextExtractionTaskConfig(self::SOME_MANUAL_CHECK); $expected = [ + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, 'manual_check' => self::SOME_MANUAL_CHECK, ]; @@ -45,8 +46,8 @@ public function shouldSerializeToJsonCorrectlyWithAllProperties() $expected = [ 'manual_check' => self::SOME_MANUAL_CHECK, - 'chip_data' => self::SOME_CHIP_DATA, - 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, + 'chip_data' => self::SOME_CHIP_DATA ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); From baed4cf41a46dd53c82937302183674f689d1e43 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 08:03:37 +0100 Subject: [PATCH 09/19] SDK-2336:Update tests --- .../RequestedSupplementaryDocTextExtractionTaskConfigTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php index 7023785e..e7a771e4 100644 --- a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php @@ -26,7 +26,6 @@ public function shouldSerializeToJsonCorrectlyWithRequiredProperties() $expected = [ 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, 'manual_check' => self::SOME_MANUAL_CHECK - ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); From e3b2c50f582de76f1aede32bd9676d0bfd679e54 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 08:08:39 +0100 Subject: [PATCH 10/19] SDK-2336:Update tests --- ...equestedSupplementaryDocTextExtractionTaskConfigTest.php | 1 - .../Create/Task/RequestedTextExtractionTaskConfigTest.php | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php index e7a771e4..e7de54b4 100644 --- a/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedSupplementaryDocTextExtractionTaskConfigTest.php @@ -24,7 +24,6 @@ public function shouldSerializeToJsonCorrectlyWithRequiredProperties() $result = new RequestedSupplementaryDocTextExtractionTaskConfig(self::SOME_MANUAL_CHECK); $expected = [ - 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, 'manual_check' => self::SOME_MANUAL_CHECK ]; diff --git a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php index e9920f82..825a3a35 100644 --- a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php @@ -26,8 +26,8 @@ public function shouldSerializeToJsonCorrectlyWithRequiredProperties() $result = new RequestedTextExtractionTaskConfig(self::SOME_MANUAL_CHECK); $expected = [ - 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, 'manual_check' => self::SOME_MANUAL_CHECK, + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); @@ -46,8 +46,8 @@ public function shouldSerializeToJsonCorrectlyWithAllProperties() $expected = [ 'manual_check' => self::SOME_MANUAL_CHECK, - 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS, - 'chip_data' => self::SOME_CHIP_DATA + 'chip_data' => self::SOME_CHIP_DATA, + 'create_expanded_document_fields' => self::SOME_EXPANDED_DOCUMENT_FIELDS ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); From 23980e3f258b6787e0aeea03eaadd861acb6f50d Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 08:10:48 +0100 Subject: [PATCH 11/19] SDK-2336:Update tests --- .../Create/Task/RequestedTextExtractionTaskConfigTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php index 825a3a35..1ee04962 100644 --- a/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php +++ b/tests/DocScan/Session/Create/Task/RequestedTextExtractionTaskConfigTest.php @@ -12,7 +12,7 @@ class RequestedTextExtractionTaskConfigTest extends TestCase { private const SOME_MANUAL_CHECK = 'someManualCheck'; private const SOME_CHIP_DATA = 'someChipData'; - private const SOME_EXPANDED_DOCUMENT_FIELDS = 'false'; + private const SOME_EXPANDED_DOCUMENT_FIELDS = false; /** From 43f91e792f5c425e0df56bfc44227c592002e6c4 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 08:33:35 +0100 Subject: [PATCH 12/19] SDK-2311:Added set setting for biometric consent screen --- src/DocScan/Session/Create/SdkConfig.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/DocScan/Session/Create/SdkConfig.php b/src/DocScan/Session/Create/SdkConfig.php index 453ad44a..07bfd854 100644 --- a/src/DocScan/Session/Create/SdkConfig.php +++ b/src/DocScan/Session/Create/SdkConfig.php @@ -63,6 +63,11 @@ class SdkConfig implements \JsonSerializable */ private $attemptsConfiguration; + /** + * @var string|null + */ + private $biometricConsentFlow; + /** * @param string|null $allowedCaptureMethods * @param string|null $primaryColour @@ -75,6 +80,7 @@ class SdkConfig implements \JsonSerializable * @param string|null $privacyPolicyUrl * @param bool|null $allowHandoff * @param array|null $idDocumentTextDataExtractionRetriesConfig + * @param string|null $biometricConsentFlow */ public function __construct( ?string $allowedCaptureMethods, @@ -87,7 +93,9 @@ public function __construct( ?string $errorUrl, ?string $privacyPolicyUrl = null, ?bool $allowHandoff = null, - ?array $idDocumentTextDataExtractionRetriesConfig = null + ?array $idDocumentTextDataExtractionRetriesConfig = null, + ?string $biometricConsentFlow = null + ) { $this->allowedCaptureMethods = $allowedCaptureMethods; $this->primaryColour = $primaryColour; @@ -102,6 +110,8 @@ public function __construct( if (!is_null($idDocumentTextDataExtractionRetriesConfig)) { $this->attemptsConfiguration = new AttemptsConfiguration($idDocumentTextDataExtractionRetriesConfig); } + $this->biometricConsentFlow = $biometricConsentFlow; + } /** @@ -121,6 +131,7 @@ public function jsonSerialize(): \stdClass 'privacy_policy_url' => $this->getPrivacyPolicyUrl(), 'allow_handoff' => $this->getAllowHandoff(), 'attempts_configuration' => $this->getAttemptsConfiguration(), + 'biometric_consent_flow' => $this->getBiometricConsentFlow() ]); } @@ -211,4 +222,12 @@ public function getAttemptsConfiguration(): ?AttemptsConfiguration { return $this->attemptsConfiguration; } + + /** + * @return string|null + */ + public function getBiometricConsentFlow(): ?string + { + return $this->privacyPolicyUrl; + } } From 397c10ef78e7245fd55fb4ec1bbf6740c345b90f Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 08:49:11 +0100 Subject: [PATCH 13/19] SDK-2311:Added set setting for biometric consent screen --- src/DocScan/Session/Create/SdkConfig.php | 2 +- tests/DocScan/Session/Create/SdkConfigBuilderTest.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/DocScan/Session/Create/SdkConfig.php b/src/DocScan/Session/Create/SdkConfig.php index 07bfd854..51b85112 100644 --- a/src/DocScan/Session/Create/SdkConfig.php +++ b/src/DocScan/Session/Create/SdkConfig.php @@ -228,6 +228,6 @@ public function getAttemptsConfiguration(): ?AttemptsConfiguration */ public function getBiometricConsentFlow(): ?string { - return $this->privacyPolicyUrl; + return $this->biometricConsentFlow; } } diff --git a/tests/DocScan/Session/Create/SdkConfigBuilderTest.php b/tests/DocScan/Session/Create/SdkConfigBuilderTest.php index 5377c5b9..3c84f5d2 100644 --- a/tests/DocScan/Session/Create/SdkConfigBuilderTest.php +++ b/tests/DocScan/Session/Create/SdkConfigBuilderTest.php @@ -22,6 +22,8 @@ class SdkConfigBuilderTest extends TestCase private const SOME_PRIVACY_POLICY_URL = 'somePrivacyPolicyUrl'; private const SOME_CATEGORY = 'someCategory'; private const SOME_NUMBER_RETRIES = 5; + private const SOME_BIOMETRIC_CONSENT_FLOW = 'someBiometricConsentFlow'; + /** * @test @@ -118,6 +120,7 @@ public function shouldProduceTheCorrectJsonString() ->withErrorUrl(self::SOME_ERROR_URL) ->withPrivacyPolicyUrl(self::SOME_PRIVACY_POLICY_URL) ->withAllowHandoff(true) + ->withBiometricConsentFlow(self::SOME_BIOMETRIC_CONSENT_FLOW) ->build(); $expected = [ @@ -131,6 +134,7 @@ public function shouldProduceTheCorrectJsonString() 'error_url' => self::SOME_ERROR_URL, 'privacy_policy_url' => self::SOME_PRIVACY_POLICY_URL, 'allow_handoff' => true, + 'biometric_consent_flow' => self::SOME_BIOMETRIC_CONSENT_FLOW ]; $this->assertJsonStringEqualsJsonString(json_encode($expected), json_encode($result)); From 7a5fb99b5be82bd18d33774ba6d73f96be526f22 Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 09:32:31 +0100 Subject: [PATCH 14/19] SDK-2311:Added set setting for biometric consent screen --- examples/doc-scan/app/Http/Controllers/HomeController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/doc-scan/app/Http/Controllers/HomeController.php b/examples/doc-scan/app/Http/Controllers/HomeController.php index 5aae0ea8..bb50054b 100644 --- a/examples/doc-scan/app/Http/Controllers/HomeController.php +++ b/examples/doc-scan/app/Http/Controllers/HomeController.php @@ -136,6 +136,7 @@ public function show(Request $request, DocScanClient $client) ->withSuccessUrl(config('app.url') . '/success') ->withErrorUrl(config('app.url') . '/error') ->withPrivacyPolicyUrl(config('app.url') . '/privacy-policy') + ->withBiometricConsentFlow('EARLY') ->build() ) ->withRequiredDocument( From 7c46be2b293d0bc4f790dbd7ca1c72e94a71e7fa Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Fri, 7 Jul 2023 10:40:07 +0100 Subject: [PATCH 15/19] SDK-2311:Added set setting for biometric consent screen --- src/DocScan/Session/Create/SdkConfigBuilder.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/DocScan/Session/Create/SdkConfigBuilder.php b/src/DocScan/Session/Create/SdkConfigBuilder.php index c91adc05..acf30fcc 100644 --- a/src/DocScan/Session/Create/SdkConfigBuilder.php +++ b/src/DocScan/Session/Create/SdkConfigBuilder.php @@ -66,6 +66,11 @@ class SdkConfigBuilder */ private $idDocumentTextDataExtractionRetriesConfig; + /** + * @var string|null + */ + private $biometricConsentFlow; + public function withAllowsCamera(): self { return $this->withAllowedCaptureMethod(self::CAMERA); @@ -136,6 +141,11 @@ public function withAllowHandoff(bool $allowHandoff): self return $this; } + public function withBiometricConsentFlow(string $biometricConsentFlow): self + { + $this->biometricConsentFlow = $biometricConsentFlow; + return $this; + } /** * Allows configuring the number of attempts permitted for text extraction on an ID document * @@ -203,7 +213,8 @@ public function build(): SdkConfig $this->errorUrl, $this->privacyPolicyUrl, $this->allowHandoff, - $this->idDocumentTextDataExtractionRetriesConfig + $this->idDocumentTextDataExtractionRetriesConfig, + $this->biometricConsentFlow ); } } From 5f6479c2ef2dfa24106e9139f7ec94d69488a342 Mon Sep 17 00:00:00 2001 From: Rodion Liuborets Date: Tue, 7 Feb 2023 22:57:32 +0200 Subject: [PATCH 16/19] Master -> Development (#315) * Release 4.1.0 * Add helper method to GetSessionResult getFaceComparisonChecks * Add several fixes, update php8.0 -> 8.1, guzzlehttp/guzzle -> 7.0, guzzlehttp/psr7 -> 2.4 * Update github actions php8.0 -> 8.1 * Update github actions for sonar check php8.0 -> 8.1 * Remove support of php7.1 * Modify sonar config for php8.1 * Add php7.4, php8.0 support * Add php7.4, php8.0 support * Update README.md (#306) * Updated dependencies * Fixed psr/log for php7.4 * Improve identity report view * Fix version to 4.2.0 (#314) From c8f546a9742050bfcd104b90c127a0e073c4610a Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Wed, 12 Jul 2023 14:15:06 +0100 Subject: [PATCH 17/19] SDK-2347 fix bug on tags attribute when its missing --- .../Retrieve/CustomAccountWatchlistCaSearchConfigResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DocScan/Session/Retrieve/CustomAccountWatchlistCaSearchConfigResponse.php b/src/DocScan/Session/Retrieve/CustomAccountWatchlistCaSearchConfigResponse.php index d1372b54..efa7819d 100644 --- a/src/DocScan/Session/Retrieve/CustomAccountWatchlistCaSearchConfigResponse.php +++ b/src/DocScan/Session/Retrieve/CustomAccountWatchlistCaSearchConfigResponse.php @@ -35,7 +35,7 @@ public function __construct(array $searchConfig) $this->apiKey = $searchConfig['api_key']; $this->monitoring = $searchConfig['monitoring']; $this->clientRef = $searchConfig['client_ref']; - $this->tags = json_decode($searchConfig['tags'], true); + $this->tags = array_key_exists('tags', $searchConfig) ? json_decode($searchConfig['tags'], true) : []; } /** From 7d158766b7aaeda05cd537f6bf85c0087638acae Mon Sep 17 00:00:00 2001 From: mehmet-yoti <111424390+mehmet-yoti@users.noreply.github.com> Date: Wed, 12 Jul 2023 18:39:54 +0300 Subject: [PATCH 18/19] Revert "SDK-2241 Share V2 Create Session (#319)" This reverts commit 6e28b4ccf143b04cdd06ce17cea5f095e03e4c57. --- .../Http/Controllers/IdentityController.php | 64 -- .../resources/views/identity.blade.php | 62 -- src/Exception/IdentityException.php | 9 - src/Identity/Constraint/Constraint.php | 8 - src/Identity/Constraint/PreferredSources.php | 54 -- src/Identity/Constraint/SourceConstraint.php | 43 -- .../Constraint/SourceConstraintBuilder.php | 46 -- .../Extension/BasicExtensionBuilder.php | 40 -- src/Identity/Extension/Extension.php | 38 -- .../Extension/ExtensionBuilderInterface.php | 8 - .../Extension/LocationConstraintContent.php | 61 -- .../LocationConstraintExtensionBuilder.php | 82 --- .../Extension/ThirdPartyAttributeContent.php | 38 -- .../ThirdPartyAttributeExtensionBuilder.php | 66 -- .../TransactionalFlowExtensionBuilder.php | 35 - src/Identity/IdentityService.php | 109 --- src/Identity/Policy/Policy.php | 75 -- src/Identity/Policy/PolicyBuilder.php | 332 --------- src/Identity/Policy/WantedAnchor.php | 29 - src/Identity/Policy/WantedAnchorBuilder.php | 32 - src/Identity/Policy/WantedAttribute.php | 123 ---- .../Policy/WantedAttributeBuilder.php | 77 --- src/Identity/ShareSessionCreated.php | 71 -- src/Identity/ShareSessionCreatedQrCode.php | 48 -- src/Identity/ShareSessionFetched.php | 117 ---- src/Identity/ShareSessionFetchedQrCode.php | 110 --- src/Identity/ShareSessionNotification.php | 70 -- .../ShareSessionNotificationBuilder.php | 65 -- src/Identity/ShareSessionRequest.php | 110 --- src/Identity/ShareSessionRequestBuilder.php | 84 --- src/Util/Validation.php | 2 +- src/YotiClient.php | 69 +- .../Constraint/PreferredSourcesTest.php | 42 -- .../SourceConstraintsBuilderTest.php | 66 -- .../Extension/BasicExtensionBuilderTest.php | 40 -- .../LocationConstraintContentTest.php | 44 -- ...LocationConstraintExtensionBuilderTest.php | 164 ----- .../ThirdPartyAttributeContentTest.php | 42 -- ...hirdPartyAttributeExtensionBuilderTest.php | 132 ---- .../TransactionalFlowExtensionBuilderTest.php | 36 - tests/Identity/IdentityServiceTest.php | 133 ---- tests/Identity/Policy/PolicyBuilderTest.php | 644 ------------------ .../Policy/WantedAnchorBuilderTest.php | 39 -- .../Policy/WantedAttributeBuilderTest.php | 162 ----- .../ShareSessionCreatedQrCodeTest.php | 42 -- tests/Identity/ShareSessionCreatedTest.php | 45 -- .../ShareSessionFetchedQrCodeTest.php | 76 --- tests/Identity/ShareSessionFetchedTest.php | 66 -- .../ShareSessionNotificationBuilderTest.php | 80 --- .../ShareSessionRequestBuilderTest.php | 100 --- tests/YotiClientTest.php | 140 ---- 51 files changed, 13 insertions(+), 4257 deletions(-) delete mode 100644 examples/profile/app/Http/Controllers/IdentityController.php delete mode 100644 examples/profile/resources/views/identity.blade.php delete mode 100644 src/Exception/IdentityException.php delete mode 100644 src/Identity/Constraint/Constraint.php delete mode 100644 src/Identity/Constraint/PreferredSources.php delete mode 100644 src/Identity/Constraint/SourceConstraint.php delete mode 100644 src/Identity/Constraint/SourceConstraintBuilder.php delete mode 100644 src/Identity/Extension/BasicExtensionBuilder.php delete mode 100644 src/Identity/Extension/Extension.php delete mode 100644 src/Identity/Extension/ExtensionBuilderInterface.php delete mode 100644 src/Identity/Extension/LocationConstraintContent.php delete mode 100644 src/Identity/Extension/LocationConstraintExtensionBuilder.php delete mode 100644 src/Identity/Extension/ThirdPartyAttributeContent.php delete mode 100644 src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php delete mode 100644 src/Identity/Extension/TransactionalFlowExtensionBuilder.php delete mode 100644 src/Identity/IdentityService.php delete mode 100644 src/Identity/Policy/Policy.php delete mode 100644 src/Identity/Policy/PolicyBuilder.php delete mode 100644 src/Identity/Policy/WantedAnchor.php delete mode 100644 src/Identity/Policy/WantedAnchorBuilder.php delete mode 100644 src/Identity/Policy/WantedAttribute.php delete mode 100644 src/Identity/Policy/WantedAttributeBuilder.php delete mode 100644 src/Identity/ShareSessionCreated.php delete mode 100644 src/Identity/ShareSessionCreatedQrCode.php delete mode 100644 src/Identity/ShareSessionFetched.php delete mode 100644 src/Identity/ShareSessionFetchedQrCode.php delete mode 100644 src/Identity/ShareSessionNotification.php delete mode 100644 src/Identity/ShareSessionNotificationBuilder.php delete mode 100644 src/Identity/ShareSessionRequest.php delete mode 100644 src/Identity/ShareSessionRequestBuilder.php delete mode 100644 tests/Identity/Constraint/PreferredSourcesTest.php delete mode 100644 tests/Identity/Constraint/SourceConstraintsBuilderTest.php delete mode 100644 tests/Identity/Extension/BasicExtensionBuilderTest.php delete mode 100644 tests/Identity/Extension/LocationConstraintContentTest.php delete mode 100644 tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php delete mode 100644 tests/Identity/Extension/ThirdPartyAttributeContentTest.php delete mode 100644 tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php delete mode 100644 tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php delete mode 100644 tests/Identity/IdentityServiceTest.php delete mode 100644 tests/Identity/Policy/PolicyBuilderTest.php delete mode 100644 tests/Identity/Policy/WantedAnchorBuilderTest.php delete mode 100644 tests/Identity/Policy/WantedAttributeBuilderTest.php delete mode 100644 tests/Identity/ShareSessionCreatedQrCodeTest.php delete mode 100644 tests/Identity/ShareSessionCreatedTest.php delete mode 100644 tests/Identity/ShareSessionFetchedQrCodeTest.php delete mode 100644 tests/Identity/ShareSessionFetchedTest.php delete mode 100644 tests/Identity/ShareSessionNotificationBuilderTest.php delete mode 100644 tests/Identity/ShareSessionRequestBuilderTest.php diff --git a/examples/profile/app/Http/Controllers/IdentityController.php b/examples/profile/app/Http/Controllers/IdentityController.php deleted file mode 100644 index 61b6317b..00000000 --- a/examples/profile/app/Http/Controllers/IdentityController.php +++ /dev/null @@ -1,64 +0,0 @@ -build(); - - $redirectUri = 'https://host/redirect/'; - - $shareSessionRequest = (new ShareSessionRequestBuilder()) - ->withPolicy($policy) - ->withRedirectUri($redirectUri) - ->build(); - - $session = $client->createShareSession($shareSessionRequest); - - $createdQrCode = $client->createShareQrCode($session->getId()); - - $fetchedQrCode = $client->fetchShareQrCode($createdQrCode->getId()); - - $sessionFetched = $client->fetchShareSession($session->getId()); - - return view('identity', [ - 'title' => 'Digital Identity Complete Example', - // Creating session - 'sessionId' => $session->getId(), - 'sessionStatus' => $session->getStatus(), - 'sessionExpiry' => $session->getExpiry(), - // Creating QR code - 'createdQrCodeId' => $createdQrCode->getId(), - 'createdQrCodeUri' => $createdQrCode->getUri(), - // Fetch QR code - 'fetchedQrCodeExpiry' => $fetchedQrCode->getExpiry(), - 'fetchedQrCodeExtensions' => $fetchedQrCode->getExtensions(), - 'fetchedQrCodeRedirectUri' => $fetchedQrCode->getRedirectUri(), - 'fetchedQrCodeSessionId' => $fetchedQrCode->getSession()->getId(), - 'fetchedQrCodeSessionStatus' => $fetchedQrCode->getSession()->getStatus(), - 'fetchedQrCodeSessionExpiry' => $fetchedQrCode->getSession()->getExpiry(), - // Fetch session - 'fetchedSessionId' => $sessionFetched->getId(), - 'fetchedSessionStatus' => $sessionFetched->getStatus(), - 'fetchedSessionExpiry' => $sessionFetched->getExpiry(), - 'fetchedSessionCreated' => $sessionFetched->getCreated(), - 'fetchedSessionUpdated' => $sessionFetched->getUpdated(), - 'fetchedSessionQrCodeId' => $sessionFetched->getQrCodeId(), - 'fetchedSessionReceiptId' => $sessionFetched->getReceiptId(), - ]); - } catch (\Throwable $e) { - Log::error($e->getTraceAsString()); - throw new BadRequestHttpException($e->getMessage()); - } - } -} diff --git a/examples/profile/resources/views/identity.blade.php b/examples/profile/resources/views/identity.blade.php deleted file mode 100644 index f4523ea3..00000000 --- a/examples/profile/resources/views/identity.blade.php +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - {{ $title }} - - - - - -
-
-
- - Yoti - -
- -

Digital Identity Share Complete Example page

- -
-

Created Session

-

Id: {{$sessionId}}

-

Status: {{$sessionStatus}}

-

Expiry: {{$sessionExpiry}}

-
- -
-

Created Session QR Code

-

Id: {{$createdQrCodeId}}

-

URI: {{$createdQrCodeUri}}

-
- -
-

Fetched Session QR Code

-

Expiry: {{$fetchedQrCodeExpiry}}

-

Extensions: {{$fetchedQrCodeExtensions}}

-

Redirect URI: {{$fetchedQrCodeRedirectUri}}

-

Session ID: {{$fetchedQrCodeSessionId}}

-

Session Status: {{$fetchedQrCodeSessionStatus}}

-

Session Expiry: {{$fetchedQrCodeSessionExpiry}}

-
- -
-

Fetched Session

-

Id: {{$fetchedSessionId}}

-

Created: {{$fetchedSessionCreated}}

-

Updated: {{$fetchedSessionUpdated}}

-

Expiry: {{$fetchedSessionExpiry}}

-

Status: {{$fetchedSessionStatus}}

-

QR Code ID: {{$fetchedSessionQrCodeId}}

-

Receipt ID: {{$fetchedSessionReceiptId}}

-
- -
-
- - - \ No newline at end of file diff --git a/src/Exception/IdentityException.php b/src/Exception/IdentityException.php deleted file mode 100644 index 0c235e8b..00000000 --- a/src/Exception/IdentityException.php +++ /dev/null @@ -1,9 +0,0 @@ -wantedAnchors = $wantedAnchors; - - Validation::isBoolean($softPreference, 'soft_preference'); - $this->softPreference = $softPreference; - } - - public function jsonSerialize(): stdClass - { - return (object)[ - 'anchors' => $this->wantedAnchors, - 'soft_preference' => $this->softPreference, - ]; - } - - /** - * @return WantedAnchor[] - */ - public function getWantedAnchors(): array - { - return $this->wantedAnchors; - } - - /** - * @return bool - */ - public function isSoftPreference(): bool - { - return $this->softPreference; - } -} diff --git a/src/Identity/Constraint/SourceConstraint.php b/src/Identity/Constraint/SourceConstraint.php deleted file mode 100644 index cd903789..00000000 --- a/src/Identity/Constraint/SourceConstraint.php +++ /dev/null @@ -1,43 +0,0 @@ -type = 'SOURCE'; - - Validation::isArrayOfType($wantedAnchors, [WantedAnchor::class], 'anchors'); - $this->preferredSources = new PreferredSources($wantedAnchors, $softPreference); - } - - public function getType(): string - { - return $this->type; - } - - public function getPreferredSources(): PreferredSources - { - return $this->preferredSources; - } - - public function jsonSerialize(): object - { - return (object)[ - 'type' => $this->getType(), - 'preferred_sources' => $this->getPreferredSources(), - ]; - } -} diff --git a/src/Identity/Constraint/SourceConstraintBuilder.php b/src/Identity/Constraint/SourceConstraintBuilder.php deleted file mode 100644 index 59b62e16..00000000 --- a/src/Identity/Constraint/SourceConstraintBuilder.php +++ /dev/null @@ -1,46 +0,0 @@ -wantedAnchors = $wantedAnchors; - - return $this; - } - - public function withWantedAnchor(WantedAnchor $wantedAnchor): self - { - $this->wantedAnchors[] = $wantedAnchor; - - return $this; - } - - public function withSoftPreference(bool $softPreference): self - { - $this->softPreference = $softPreference; - - return $this; - } - - public function build(): SourceConstraint - { - return new SourceConstraint($this->wantedAnchors, $this->softPreference); - } -} diff --git a/src/Identity/Extension/BasicExtensionBuilder.php b/src/Identity/Extension/BasicExtensionBuilder.php deleted file mode 100644 index 97d913aa..00000000 --- a/src/Identity/Extension/BasicExtensionBuilder.php +++ /dev/null @@ -1,40 +0,0 @@ -type = $type; - - return $this; - } - - /** - * @param mixed $content - * - * @return $this - */ - public function withContent($content): self - { - $this->content = $content; - - return $this; - } - - public function build(): Extension - { - return new Extension($this->type, $this->content); - } -} diff --git a/src/Identity/Extension/Extension.php b/src/Identity/Extension/Extension.php deleted file mode 100644 index d7e436b1..00000000 --- a/src/Identity/Extension/Extension.php +++ /dev/null @@ -1,38 +0,0 @@ -type = $type; - - Validation::notNull($type, 'content'); - $this->content = $content; - } - - /** - * @return stdClass - */ - public function jsonSerialize(): stdClass - { - return (object)[ - 'type' => $this->type, - 'content' => $this->content, - ]; - } -} diff --git a/src/Identity/Extension/ExtensionBuilderInterface.php b/src/Identity/Extension/ExtensionBuilderInterface.php deleted file mode 100644 index 1ab39bd8..00000000 --- a/src/Identity/Extension/ExtensionBuilderInterface.php +++ /dev/null @@ -1,8 +0,0 @@ -latitude = $latitude; - - Validation::withinRange($longitude, -180, 180, 'longitude'); - $this->longitude = $longitude; - - Validation::notLessThan($radius, 0, 'radius'); - $this->radius = $radius; - - Validation::notLessThan($maxUncertainty, 0, 'maxUncertainty'); - $this->maxUncertainty = $maxUncertainty; - } - - /** - * @inheritDoc - * - * @return stdClass - */ - public function jsonSerialize(): stdClass - { - return (object)[ - 'expected_device_location' => [ - 'latitude' => $this->latitude, - 'longitude' => $this->longitude, - 'radius' => $this->radius, - 'max_uncertainty_radius' => $this->maxUncertainty, - ] - ]; - } -} diff --git a/src/Identity/Extension/LocationConstraintExtensionBuilder.php b/src/Identity/Extension/LocationConstraintExtensionBuilder.php deleted file mode 100644 index 556cd19d..00000000 --- a/src/Identity/Extension/LocationConstraintExtensionBuilder.php +++ /dev/null @@ -1,82 +0,0 @@ -latitude = $latitude; - return $this; - } - - /** - * Allows you to specify the Longitude of the user's expected location - */ - public function withLongitude(float $longitude): self - { - $this->longitude = $longitude; - return $this; - } - - /** - * Radius of the circle, centred on the specified location coordinates, where the device is - * allowed to perform the share. - * - * If not provided, a default value of 150m will be used. - * - * @param float $radius - * The allowable distance, in metres, from the given lat/long location - */ - public function withRadius(float $radius): self - { - $this->radius = $radius; - return $this; - } - - /** - * Maximum acceptable distance, in metres, of the area of uncertainty associated with the device - * location coordinates. - * - * If not provided, a default value of 150m will be used. - * - * @param float $maxUncertainty - * Maximum allowed measurement uncertainty, in metres - * - * @return $this - */ - public function withMaxUncertainty(float $maxUncertainty): self - { - $this->maxUncertainty = $maxUncertainty; - - return $this; - } - - public function build(): Extension - { - $content = new LocationConstraintContent( - $this->latitude, - $this->longitude, - $this->radius, - $this->maxUncertainty - ); - - return new Extension(self::LOCATION_CONSTRAINT, $content); - } -} diff --git a/src/Identity/Extension/ThirdPartyAttributeContent.php b/src/Identity/Extension/ThirdPartyAttributeContent.php deleted file mode 100644 index 0eeec95a..00000000 --- a/src/Identity/Extension/ThirdPartyAttributeContent.php +++ /dev/null @@ -1,38 +0,0 @@ -expiryDate = $expiryDate; - - Validation::isArrayOfType($definitions, [AttributeDefinition::class], 'definitions'); - $this->definitions = $definitions; - } - - public function jsonSerialize(): stdClass - { - return (object)[ - 'expiry_date' => $this->expiryDate - ->setTimezone(new \DateTimeZone('UTC')) - ->format(\DateTime::RFC3339_EXTENDED), - 'definitions' => $this->definitions, - ]; - } -} diff --git a/src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php b/src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php deleted file mode 100644 index 132fa720..00000000 --- a/src/Identity/Extension/ThirdPartyAttributeExtensionBuilder.php +++ /dev/null @@ -1,66 +0,0 @@ -expiryDate = $expiryDate; - - return $this; - } - - public function withDefinition(string $definition): self - { - $this->definitions[] = new AttributeDefinition($definition); - - return $this; - } - - /** - * @param string[] $definitions - */ - public function withDefinitions(array $definitions): self - { - Validation::isArrayOfStrings($definitions, 'definitions'); - $this->definitions = array_map( - function ($definition): AttributeDefinition { - return new AttributeDefinition($definition); - }, - $definitions - ); - - return $this; - } - - public function build(): Extension - { - return new Extension( - self::THIRD_PARTY_ATTRIBUTE, - new ThirdPartyAttributeContent( - $this->expiryDate, - $this->definitions - ) - ); - } -} diff --git a/src/Identity/Extension/TransactionalFlowExtensionBuilder.php b/src/Identity/Extension/TransactionalFlowExtensionBuilder.php deleted file mode 100644 index 22eb5821..00000000 --- a/src/Identity/Extension/TransactionalFlowExtensionBuilder.php +++ /dev/null @@ -1,35 +0,0 @@ -content = $content; - - return $this; - } - - /** - * @return Extension with TRANSACTIONAL_FLOW type - */ - public function build(): Extension - { - return new Extension(static::TYPE, $this->content); - } -} diff --git a/src/Identity/IdentityService.php b/src/Identity/IdentityService.php deleted file mode 100644 index edbf96f5..00000000 --- a/src/Identity/IdentityService.php +++ /dev/null @@ -1,109 +0,0 @@ -sdkId = $sdkId; - $this->pemFile = $pemFile; - $this->config = $config; - } - - public function createShareSession(ShareSessionRequest $shareSessionRequest): ShareSessionCreated - { - $response = (new RequestBuilder($this->config)) - ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) - ->withEndpoint(self::IDENTITY_SESSION_CREATION) - ->withHeader('X-Yoti-Auth-Id', $this->sdkId) - ->withPost() - ->withPayload(Payload::fromJsonData($shareSessionRequest)) - ->withPemFile($this->pemFile) - ->build() - ->execute(); - - $httpCode = $response->getStatusCode(); - if ($httpCode < 200 || $httpCode > 299) { - throw new IdentityException("Server responded with {$httpCode}", $response); - } - - return new ShareSessionCreated(Json::decode((string)$response->getBody())); - } - - public function createShareQrCode(string $sessionId): ShareSessionCreatedQrCode - { - $response = (new RequestBuilder($this->config)) - ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) - ->withEndpoint(sprintf(self::IDENTITY_SESSION_QR_CODE_CREATION, $sessionId)) - ->withHeader('X-Yoti-Auth-Id', $this->sdkId) - ->withPost() - ->withPemFile($this->pemFile) - ->build() - ->execute(); - - $httpCode = $response->getStatusCode(); - if ($httpCode < 200 || $httpCode > 299) { - throw new IdentityException("Server responded with {$httpCode}", $response); - } - - return new ShareSessionCreatedQrCode(Json::decode((string)$response->getBody())); - } - - public function fetchShareQrCode(string $qrCodeId): ShareSessionFetchedQrCode - { - $response = (new RequestBuilder($this->config)) - ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) - ->withEndpoint(sprintf(self::IDENTITY_SESSION_QR_CODE_RETRIEVAL, $qrCodeId)) - ->withHeader('X-Yoti-Auth-Id', $this->sdkId) - ->withPost() - ->withPemFile($this->pemFile) - ->build() - ->execute(); - - $httpCode = $response->getStatusCode(); - if ($httpCode < 200 || $httpCode > 299) { - throw new IdentityException("Server responded with {$httpCode}", $response); - } - - return new ShareSessionFetchedQrCode(Json::decode((string)$response->getBody())); - } - - public function fetchShareSession(string $sessionId): ShareSessionFetched - { - $response = (new RequestBuilder($this->config)) - ->withBaseUrl($this->config->getApiUrl() ?? Constants::API_URL) - ->withEndpoint(sprintf(self::IDENTITY_SESSION_RETRIEVAL, $sessionId)) - ->withHeader('X-Yoti-Auth-Id', $this->sdkId) - ->withPost() - ->withPemFile($this->pemFile) - ->build() - ->execute(); - - $httpCode = $response->getStatusCode(); - if ($httpCode < 200 || $httpCode > 299) { - throw new IdentityException("Server responded with {$httpCode}", $response); - } - - return new ShareSessionFetched(Json::decode((string)$response->getBody())); - } -} diff --git a/src/Identity/Policy/Policy.php b/src/Identity/Policy/Policy.php deleted file mode 100644 index 62ade060..00000000 --- a/src/Identity/Policy/Policy.php +++ /dev/null @@ -1,75 +0,0 @@ -wantedAttributes = $wantedAttributes; - - Validation::isArrayOfIntegers($wantedAuthTypes, 'wantedAuthTypes'); - $this->wantedAuthTypes = $wantedAuthTypes; - - $this->wantedRememberMe = $wantedRememberMe; - $this->wantedRememberMeOptional = $wantedRememberMeOptional; - $this->identityProfileRequirements = $identityProfileRequirements; - } - - - public function jsonSerialize(): stdClass - { - return (object)[ - 'wanted' => $this->wantedAttributes, - 'wanted_auth_types' => $this->wantedAuthTypes, - 'wanted_remember_me' => $this->wantedRememberMe, - 'wanted_remember_me_optional' => $this->wantedRememberMeOptional, - 'identity_profile_requirements' => $this->identityProfileRequirements, - ]; - } - - /** - * IdentityProfileRequirements requested in the policy - * - * @return object|null - */ - public function getIdentityProfileRequirements() - { - return $this->identityProfileRequirements; - } -} diff --git a/src/Identity/Policy/PolicyBuilder.php b/src/Identity/Policy/PolicyBuilder.php deleted file mode 100644 index e8a8b190..00000000 --- a/src/Identity/Policy/PolicyBuilder.php +++ /dev/null @@ -1,332 +0,0 @@ -getName(); - - if (null !== $wantedAttribute->getDerivation()) { - $key = $wantedAttribute->getDerivation(); - } - - if (null !== $wantedAttribute->getConstraints()) { - $key .= '-' . hash('sha256', Json::encode($wantedAttribute->getConstraints())); - } - - $this->wantedAttributes[$key] = $wantedAttribute; - - return $this; - } - - /** - * @param Constraint[]|null $constraints - */ - public function withWantedAttributeByName( - string $name, - array $constraints = null, - bool $acceptSelfAsserted = null - ): self { - $wantedAttributeBuilder = (new WantedAttributeBuilder()) - ->withName($name); - - if ($constraints !== null) { - $wantedAttributeBuilder->withConstraints($constraints); - } - - if ($acceptSelfAsserted !== null) { - $wantedAttributeBuilder->withAcceptSelfAsserted($acceptSelfAsserted); - } - - return $this->withWantedAttribute($wantedAttributeBuilder->build()); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withFamilyName(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_FAMILY_NAME, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withGivenNames(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_GIVEN_NAMES, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withFullName(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_FULL_NAME, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withDateOfBirth(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_DATE_OF_BIRTH, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withAgeOver(int $age, array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withAgeDerivedAttribute( - UserProfile::AGE_OVER . $age, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withAgeUnder(int $age, array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withAgeDerivedAttribute( - UserProfile::AGE_UNDER . $age, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withAgeDerivedAttribute( - string $derivation, - array $constraints = null, - bool $acceptSelfAsserted = null - ): self { - $wantedAttributeBuilder = (new WantedAttributeBuilder()) - ->withName(UserProfile::ATTR_DATE_OF_BIRTH) - ->withDerivation($derivation); - - if ($constraints !== null) { - $wantedAttributeBuilder->withConstraints($constraints); - } - - if ($acceptSelfAsserted !== null) { - $wantedAttributeBuilder->withAcceptSelfAsserted($acceptSelfAsserted); - } - - return $this->withWantedAttribute($wantedAttributeBuilder->build()); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withGender(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_GENDER, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withPostalAddress(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_POSTAL_ADDRESS, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withStructuredPostalAddress(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_STRUCTURED_POSTAL_ADDRESS, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withNationality(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_NATIONALITY, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withPhoneNumber(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_PHONE_NUMBER, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withSelfie(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_SELFIE, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withDocumentDetails(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_DOCUMENT_DETAILS, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withDocumentImages(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_DOCUMENT_IMAGES, - $constraints, - $acceptSelfAsserted - ); - } - - /** - * @param Constraint[]|null $constraints - */ - public function withEmail(array $constraints = null, bool $acceptSelfAsserted = null): self - { - return $this->withWantedAttributeByName( - UserProfile::ATTR_EMAIL_ADDRESS, - $constraints, - $acceptSelfAsserted - ); - } - - - public function withSelfieAuthentication(bool $enabled = true): self - { - return $this->withWantedAuthType(self::SELFIE_AUTH_TYPE, $enabled); - } - - - public function withPinAuthentication(bool $enabled = true): self - { - return $this->withWantedAuthType(self::PIN_AUTH_TYPE, $enabled); - } - - public function withWantedAuthType(int $wantedAuthType, bool $enabled = true): self - { - if ($enabled) { - $this->wantedAuthTypes[$wantedAuthType] = $wantedAuthType; - } else { - unset($this->wantedAuthTypes[$wantedAuthType]); - } - - return $this; - } - - - public function withWantedRememberMe(bool $wantedRememberMe): self - { - $this->wantedRememberMe = $wantedRememberMe; - return $this; - } - - public function withWantedRememberMeOptional(bool $wantedRememberMeOptional): self - { - $this->wantedRememberMeOptional = $wantedRememberMeOptional; - return $this; - } - - /** - * Use an Identity Profile Requirement object for the share - * - * @param object $identityProfileRequirements - * @return $this - */ - public function withIdentityProfileRequirements($identityProfileRequirements): self - { - $this->identityProfileRequirements = $identityProfileRequirements; - return $this; - } - - - public function build(): Policy - { - return new Policy( - array_values($this->wantedAttributes), - array_values($this->wantedAuthTypes), - $this->wantedRememberMe, - $this->wantedRememberMeOptional, - $this->identityProfileRequirements - ); - } -} diff --git a/src/Identity/Policy/WantedAnchor.php b/src/Identity/Policy/WantedAnchor.php deleted file mode 100644 index 1714ca8a..00000000 --- a/src/Identity/Policy/WantedAnchor.php +++ /dev/null @@ -1,29 +0,0 @@ -value = $value; - $this->subType = $subType; - } - - public function jsonSerialize(): stdClass - { - return (object)[ - 'name' => $this->value, - 'sub_type' => $this->subType, - ]; - } -} diff --git a/src/Identity/Policy/WantedAnchorBuilder.php b/src/Identity/Policy/WantedAnchorBuilder.php deleted file mode 100644 index 9625445f..00000000 --- a/src/Identity/Policy/WantedAnchorBuilder.php +++ /dev/null @@ -1,32 +0,0 @@ -value = $value; - return $this; - } - - public function withSubType(string $subType): self - { - $this->subType = $subType; - return $this; - } - - public function build(): WantedAnchor - { - Validation::notNull($this->value, 'value'); - Validation::notNull($this->subType, 'sub_type'); - - return new WantedAnchor($this->value, $this->subType); - } -} diff --git a/src/Identity/Policy/WantedAttribute.php b/src/Identity/Policy/WantedAttribute.php deleted file mode 100644 index dc34da79..00000000 --- a/src/Identity/Policy/WantedAttribute.php +++ /dev/null @@ -1,123 +0,0 @@ -name = $name; - - $this->derivation = $derivation; - $this->optional = $optional; - $this->acceptSelfAsserted = $acceptSelfAsserted; - - if (null !== $constraints) { - Validation::isArrayOfType($constraints, [Constraint::class], 'constraints'); - $this->constraints = $constraints; - } - } - - /** - * Name identifying the WantedAttribute - * - * @return string - */ - public function getName(): string - { - return $this->name; - } - - /** - * Additional derived criteria. - * - * @return string - */ - public function getDerivation(): ?string - { - return $this->derivation; - } - - /** - * List of constraints to add to an attribute. - * - * If you do not provide any particular constraints, Yoti will provide you with the - * information from the most recently added source. - * - * @return Constraint[] $constraints - */ - public function getConstraints(): ?array - { - return $this->constraints; - } - - /** - * Accept self asserted attributes. - * - * These are attributes that have been self-declared, and not verified by Yoti. - * - * @return bool|null - */ - public function getAcceptSelfAsserted(): ?bool - { - return $this->acceptSelfAsserted; - } - - /** - * @return bool - */ - public function getOptional(): bool - { - return $this->optional; - } - - public function jsonSerialize(): stdClass - { - $data = new stdClass(); - $data->name = $this->getName(); - $data->optional = $this->getOptional(); - - if (null !== $this->getDerivation()) { - $data->derivation = $this->getDerivation(); - } - - if (null !== $this->getConstraints()) { - $data->constraints = $this->getConstraints(); - } - - if (null !== $this->getAcceptSelfAsserted()) { - $data->accept_self_asserted = $this->getAcceptSelfAsserted(); - } - - return $data; - } -} diff --git a/src/Identity/Policy/WantedAttributeBuilder.php b/src/Identity/Policy/WantedAttributeBuilder.php deleted file mode 100644 index c2a53f1f..00000000 --- a/src/Identity/Policy/WantedAttributeBuilder.php +++ /dev/null @@ -1,77 +0,0 @@ -name = $name; - - return $this; - } - - public function withDerivation(string $derivation): self - { - $this->derivation = $derivation; - - return $this; - } - - public function withOptional(bool $optional): self - { - $this->optional = $optional; - - return $this; - } - - public function withAcceptSelfAsserted(bool $acceptSelfAsserted): self - { - $this->acceptSelfAsserted = $acceptSelfAsserted; - - return $this; - } - - /** - * @param Constraint[] $constraints - */ - public function withConstraints(array $constraints): self - { - $this->constraints = $constraints; - - return $this; - } - - public function withConstraint(Constraint $constraint): self - { - $this->constraints[] = $constraint; - - return $this; - } - - public function build(): WantedAttribute - { - return new WantedAttribute( - $this->name, - $this->derivation, - $this->optional, - $this->acceptSelfAsserted, - $this->constraints, - ); - } -} diff --git a/src/Identity/ShareSessionCreated.php b/src/Identity/ShareSessionCreated.php deleted file mode 100644 index 4bb0f924..00000000 --- a/src/Identity/ShareSessionCreated.php +++ /dev/null @@ -1,71 +0,0 @@ -id = $sessionData['id']; - } - - if (isset($sessionData['status'])) { - Validation::isString($sessionData['status'], 'status'); - $this->status = $sessionData['status']; - } - - if (isset($sessionData['expiry'])) { - Validation::isString($sessionData['expiry'], 'expiry'); - $this->expiry = $sessionData['expiry']; - } - } - - /** - * @return string - */ - public function getId(): string - { - return $this->id; - } - - /** - * @return string - */ - public function getStatus(): string - { - return $this->status; - } - - /** - * @return string - */ - public function getExpiry(): string - { - return $this->expiry; - } - - public function jsonSerialize(): object - { - return (object)[ - 'id' => $this->getId(), - 'status' => $this->getStatus(), - 'expiry' => $this->getExpiry(), - ]; - } -} diff --git a/src/Identity/ShareSessionCreatedQrCode.php b/src/Identity/ShareSessionCreatedQrCode.php deleted file mode 100644 index 901074b0..00000000 --- a/src/Identity/ShareSessionCreatedQrCode.php +++ /dev/null @@ -1,48 +0,0 @@ -id = $sessionData['id']; - } - - if (isset($sessionData['uri'])) { - $this->uri = $sessionData['uri']; - } - } - - public function jsonSerialize(): object - { - return (object)[ - 'id' => $this->id, - 'uri' => $this->uri - ]; - } - - /** - * @return string - */ - public function getId(): string - { - return $this->id; - } - - /** - * @return string - */ - public function getUri(): string - { - return $this->uri; - } -} diff --git a/src/Identity/ShareSessionFetched.php b/src/Identity/ShareSessionFetched.php deleted file mode 100644 index ac171a2f..00000000 --- a/src/Identity/ShareSessionFetched.php +++ /dev/null @@ -1,117 +0,0 @@ - $sessionData - */ - public function __construct(array $sessionData) - { - if (isset($sessionData['id'])) { - $this->id = $sessionData['id']; - } - if (isset($sessionData['status'])) { - $this->status = $sessionData['status']; - } - if (isset($sessionData['expiry'])) { - $this->expiry = $sessionData['expiry']; - } - if (isset($sessionData['created'])) { - $this->created = $sessionData['created']; - } - if (isset($sessionData['updated'])) { - $this->updated = $sessionData['updated']; - } - if (isset($sessionData['qrCode'])) { - $this->qrCodeId = $sessionData['qrCode']['id']; - } - if (isset($sessionData['receipt'])) { - $this->receiptId = $sessionData['receipt']['id']; - } - } - - public function jsonSerialize(): object - { - return (object)[ - 'id' => $this->id, - 'status' => $this->status, - 'expiry' => $this->expiry, - 'created' => $this->created, - 'updated' => $this->updated, - 'qrCodeId' => $this->qrCodeId, - 'receiptId' => $this->receiptId, - ]; - } - - /** - * @return string - */ - public function getId(): string - { - return $this->id; - } - - /** - * @return string - */ - public function getStatus(): string - { - return $this->status; - } - - /** - * @return string - */ - public function getCreated(): string - { - return $this->created; - } - - /** - * @return string - */ - public function getUpdated(): string - { - return $this->updated; - } - - /** - * @return string - */ - public function getExpiry(): string - { - return $this->expiry; - } - - /** - * @return string - */ - public function getQrCodeId(): string - { - return $this->qrCodeId; - } - - /** - * @return string - */ - public function getReceiptId(): string - { - return $this->receiptId; - } -} diff --git a/src/Identity/ShareSessionFetchedQrCode.php b/src/Identity/ShareSessionFetchedQrCode.php deleted file mode 100644 index 1f8aaabf..00000000 --- a/src/Identity/ShareSessionFetchedQrCode.php +++ /dev/null @@ -1,110 +0,0 @@ - $sessionData - */ - public function __construct(array $sessionData) - { - if (isset($sessionData['id'])) { - $this->id = $sessionData['id']; - } - if (isset($sessionData['expiry'])) { - $this->expiry = $sessionData['expiry']; - } - if (isset($sessionData['policy'])) { - $this->policy = $sessionData['policy']; - } - if (isset($sessionData['extensions'])) { - foreach ($sessionData['extensions'] as $extension) { - $this->extensions[] = new Extension($extension['type'], $extension['content']); - } - } - if (isset($sessionData['session'])) { - $this->session = new ShareSessionCreated($sessionData['session']); - } - if (isset($sessionData['redirectUri'])) { - $this->redirectUri = $sessionData['redirectUri']; - } - } - - public function jsonSerialize(): object - { - return (object)[ - 'id' => $this->id, - 'expiry' => $this->expiry, - 'policy' => $this->policy, - 'extensions' => $this->extensions, - 'session' => $this->session, - 'redirectUri' => $this->redirectUri, - ]; - } - - /** - * @return string - */ - public function getId(): string - { - return $this->id; - } - - /** - * @return string - */ - public function getExpiry(): string - { - return $this->expiry; - } - - /** - * @return string - */ - public function getPolicy(): string - { - return $this->policy; - } - - /** - * @return Extension[] - */ - public function getExtensions(): array - { - return $this->extensions; - } - - /** - * @return ShareSessionCreated - */ - public function getSession(): ShareSessionCreated - { - return $this->session; - } - - /** - * @return string - */ - public function getRedirectUri(): string - { - return $this->redirectUri; - } -} diff --git a/src/Identity/ShareSessionNotification.php b/src/Identity/ShareSessionNotification.php deleted file mode 100644 index 5a6fc24f..00000000 --- a/src/Identity/ShareSessionNotification.php +++ /dev/null @@ -1,70 +0,0 @@ - - */ - private array $headers; - - /** - * @param string[] $headers - */ - public function __construct(string $url, string $method, bool $verifyTls, array $headers) - { - $this->url = $url; - $this->method = $method; - $this->verifyTls = $verifyTls; - $this->headers = $headers; - } - - public function jsonSerialize(): object - { - return (object)[ - 'url' => $this->getUrl(), - 'method' => $this->getMethod(), - 'verifyTls' => $this->isVerifyTls(), - 'headers' => $this->getHeaders(), - ]; - } - - /** - * @return string - */ - public function getUrl(): string - { - return $this->url; - } - - /** - * @return string - */ - public function getMethod(): string - { - return $this->method; - } - - /** - * @return bool - */ - public function isVerifyTls(): bool - { - return $this->verifyTls; - } - - /** - * @return string[] - */ - public function getHeaders(): array - { - return $this->headers; - } -} diff --git a/src/Identity/ShareSessionNotificationBuilder.php b/src/Identity/ShareSessionNotificationBuilder.php deleted file mode 100644 index 39d7aba3..00000000 --- a/src/Identity/ShareSessionNotificationBuilder.php +++ /dev/null @@ -1,65 +0,0 @@ - - */ - private array $headers; - - public function withUrl(string $url): self - { - $this->url = $url; - - return $this; - } - - public function withMethod(string $method = 'POST'): self - { - $this->method = $method; - - return $this; - } - - public function withVerifyTls(bool $verifyTls = true): self - { - $this->verifyTls = $verifyTls; - - return $this; - } - - /** - * @param string[] $headers - */ - public function withHeaders(array $headers): self - { - $this->headers = $headers; - - return $this; - } - - public function withHeader(string $key, string $header): self - { - $this->headers[$key] = $header; - - return $this; - } - - public function build(): ShareSessionNotification - { - return new ShareSessionNotification( - $this->url, - $this->method, - $this->verifyTls, - $this->headers - ); - } -} diff --git a/src/Identity/ShareSessionRequest.php b/src/Identity/ShareSessionRequest.php deleted file mode 100644 index 94e9cadb..00000000 --- a/src/Identity/ShareSessionRequest.php +++ /dev/null @@ -1,110 +0,0 @@ -|null - */ - private ?array $subject; - - private Policy $policy; - - /** - * @var Extension[]|null - */ - private ?array $extensions = null; - - private string $redirectUri; - - private ?ShareSessionNotification $notification; - - /** - * @param array|null $subject - * @param Policy $policy - * @param Extension[]|null $extensions - * @param string $redirectUri - * @param ShareSessionNotification|null $notification - */ - public function __construct( - Policy $policy, - string $redirectUri, - ?array $extensions = null, - ?array $subject = null, - ?ShareSessionNotification $notification = null - ) { - $this->policy = $policy; - $this->redirectUri = $redirectUri; - - if (null !== $extensions) { - Validation::isArrayOfType($extensions, [Extension::class], 'extensions'); - $this->extensions = $extensions; - } - - $this->subject = $subject; - $this->notification = $notification; - } - - /** - * @return array|null - */ - public function getSubject(): ?array - { - return $this->subject; - } - - /** - * @return Policy - */ - public function getPolicy(): Policy - { - return $this->policy; - } - - /** - * @return Extension[]|null - */ - public function getExtensions(): ?array - { - return $this->extensions; - } - - /** - * @return string - */ - public function getRedirectUri(): string - { - return $this->redirectUri; - } - - /** - * @return ShareSessionNotification|null - */ - public function getNotification(): ?ShareSessionNotification - { - return $this->notification; - } - - public function jsonSerialize(): \stdClass - { - $data = new \stdClass(); - $data->policy = $this->getPolicy(); - $data->redirectUri = $this->getRedirectUri(); - if (null !== $this->getSubject()) { - $data->subject = $this->getSubject(); - } - if (null !== $this->getExtensions()) { - $data->extensions = $this->getExtensions(); - } - if (null !== $this->getNotification()) { - $data->notification = $this->getNotification(); - } - - return $data; - } -} diff --git a/src/Identity/ShareSessionRequestBuilder.php b/src/Identity/ShareSessionRequestBuilder.php deleted file mode 100644 index 583d06fe..00000000 --- a/src/Identity/ShareSessionRequestBuilder.php +++ /dev/null @@ -1,84 +0,0 @@ - - */ - private ?array $subject = null; - - private Policy $policy; - - /** - * @var Extension[] - */ - private ?array $extensions = null; - - private string $redirectUri; - - private ?ShareSessionNotification $notification = null; - - /** - * @param array $subject - */ - public function withSubject(array $subject): self - { - $this->subject = $subject; - - return $this; - } - - public function withPolicy(Policy $policy): self - { - $this->policy = $policy; - - return $this; - } - - /** - * @param Extension[] $extensions - */ - public function withExtensions(array $extensions): self - { - $this->extensions = $extensions; - - return $this; - } - - public function withExtension(Extension $extension): self - { - $this->extensions[] = $extension; - - return $this; - } - - public function withRedirectUri(string $redirectUri): self - { - $this->redirectUri = $redirectUri; - - return $this; - } - - public function withNotification(ShareSessionNotification $notification): ShareSessionRequestBuilder - { - $this->notification = $notification; - - return $this; - } - - public function build(): ShareSessionRequest - { - return new ShareSessionRequest( - $this->policy, - $this->redirectUri, - $this->extensions, - $this->subject, - $this->notification - ); - } -} diff --git a/src/Util/Validation.php b/src/Util/Validation.php index c998db56..1bfbb82c 100644 --- a/src/Util/Validation.php +++ b/src/Util/Validation.php @@ -40,7 +40,7 @@ public static function isBoolean($value, $name): void */ public static function notNull($value, string $name): void { - if (null === $value) { + if (is_null($value)) { throw new \InvalidArgumentException("{$name} cannot be null"); } } diff --git a/src/YotiClient.php b/src/YotiClient.php index c706ca37..54caf6bc 100644 --- a/src/YotiClient.php +++ b/src/YotiClient.php @@ -8,11 +8,8 @@ use Yoti\Aml\Result as AmlResult; use Yoti\Aml\Service as AmlService; use Yoti\Exception\ActivityDetailsException; -use Yoti\Exception\IdentityException; use Yoti\Exception\PemFileException; use Yoti\Exception\ReceiptException; -use Yoti\Identity\IdentityService; -use Yoti\Identity\ShareSessionRequest; use Yoti\Profile\ActivityDetails; use Yoti\Profile\Service as ProfileService; use Yoti\ShareUrl\DynamicScenario; @@ -31,13 +28,20 @@ */ class YotiClient { - private AmlService $amlService; - - private ProfileService $profileService; + /** + * @var AmlService + */ + private $amlService; - private ShareUrlService $shareUrlService; + /** + * @var ProfileService + */ + private $profileService; - private IdentityService $identityService; + /** + * @var ShareUrlService + */ + private $shareUrlService; /** * YotiClient constructor. @@ -67,7 +71,6 @@ public function __construct( $this->profileService = new ProfileService($sdkId, $pemFile, $config); $this->amlService = new AmlService($sdkId, $pemFile, $config); $this->shareUrlService = new ShareUrlService($sdkId, $pemFile, $config); - $this->identityService = new IdentityService($sdkId, $pemFile, $config); } /** @@ -126,52 +129,4 @@ public function createShareUrl(DynamicScenario $dynamicScenario): ShareUrlResult { return $this->shareUrlService->createShareUrl($dynamicScenario); } - - /** - * Create a sharing session to initiate a sharing process based on a policy - * - * @throws IdentityException - * - * Aggregate exception signalling issues during the call - */ - public function createShareSession(ShareSessionRequest $request): Identity\ShareSessionCreated - { - return $this->identityService->createShareSession($request); - } - - /** - * Create a sharing session QR code to initiate a sharing process based on a policy - * - * @throws IdentityException - * - * Aggregate exception signalling issues during the call - */ - public function createShareQrCode(string $sessionId): Identity\ShareSessionCreatedQrCode - { - return $this->identityService->createShareQrCode($sessionId); - } - - /** - * Retrieve the sharing session QR code - * - * @throws IdentityException - * - * Aggregate exception signalling issues during the call - */ - public function fetchShareQrCode(string $qrCodeId): Identity\ShareSessionFetchedQrCode - { - return $this->identityService->fetchShareQrCode($qrCodeId); - } - - /** - * Retrieve the sharing session - * - * @throws IdentityException - * - * Aggregate exception signalling issues during the call - */ - public function fetchShareSession(string $sessionId): Identity\ShareSessionFetched - { - return $this->identityService->fetchShareSession($sessionId); - } } diff --git a/tests/Identity/Constraint/PreferredSourcesTest.php b/tests/Identity/Constraint/PreferredSourcesTest.php deleted file mode 100644 index 8b5b4ff1..00000000 --- a/tests/Identity/Constraint/PreferredSourcesTest.php +++ /dev/null @@ -1,42 +0,0 @@ - $wantedAnchors, - 'soft_preference' => true - ]; - - $this->assertInstanceOf(PreferredSources::class, $preferredSource); - $this->assertEquals(json_encode($expected), json_encode($preferredSource)); - $this->assertEquals($wantedAnchors, $preferredSource->getWantedAnchors()); - $this->assertTrue($preferredSource->isSoftPreference()); - } -} diff --git a/tests/Identity/Constraint/SourceConstraintsBuilderTest.php b/tests/Identity/Constraint/SourceConstraintsBuilderTest.php deleted file mode 100644 index ac6423c6..00000000 --- a/tests/Identity/Constraint/SourceConstraintsBuilderTest.php +++ /dev/null @@ -1,66 +0,0 @@ -withWantedAnchor(new WantedAnchor('SOME_VALUE')) - ->withSoftPreference(true) - ->build(); - - $this->assertInstanceOf(SourceConstraint::class, $sourceConstraint); - $this->assertInstanceOf(PreferredSources::class, $sourceConstraint->getPreferredSources()); - $this->assertEquals('SOURCE', $sourceConstraint->getType()); - } - - /** - * @covers ::build - * @covers ::withWantedAnchors - * @covers \Yoti\Identity\Constraint\SourceConstraint::__construct - * @covers \Yoti\Identity\Constraint\SourceConstraint::jsonSerialize - */ - public function testShouldBuildCorrectlyWithMultipleAnchors() - { - $wantedAnchors = [ - new WantedAnchor('some'), - new WantedAnchor('some_2'), - ]; - - $sourceConstraint = (new SourceConstraintBuilder()) - ->withWantedAnchors($wantedAnchors) - ->build(); - - $expectedConstraint = [ - 'type' => 'SOURCE', - 'preferred_sources' => $sourceConstraint->getPreferredSources() - ]; - - $this->assertEquals($wantedAnchors, $sourceConstraint->getPreferredSources()->getWantedAnchors()); - $this->assertEquals( - json_encode($wantedAnchors), - json_encode($sourceConstraint->getPreferredSources()->getWantedAnchors()) - ); - $this->assertEquals(json_encode($expectedConstraint), json_encode($sourceConstraint)); - } -} diff --git a/tests/Identity/Extension/BasicExtensionBuilderTest.php b/tests/Identity/Extension/BasicExtensionBuilderTest.php deleted file mode 100644 index 026a045f..00000000 --- a/tests/Identity/Extension/BasicExtensionBuilderTest.php +++ /dev/null @@ -1,40 +0,0 @@ -withType($someType) - ->withContent($someContent) - ->build(); - - $expectedJson = json_encode([ - 'type' => $someType, - 'content' => $someContent, - ]); - - $this->assertEquals($expectedJson, json_encode($constraints)); - } -} diff --git a/tests/Identity/Extension/LocationConstraintContentTest.php b/tests/Identity/Extension/LocationConstraintContentTest.php deleted file mode 100644 index a0973db1..00000000 --- a/tests/Identity/Extension/LocationConstraintContentTest.php +++ /dev/null @@ -1,44 +0,0 @@ - [ - 'latitude' => $expectedLatitude, - 'longitude' => $expectedLongitude, - 'radius' => $expectedRadius, - 'max_uncertainty_radius' => $expectedMaxUncertainty, - ], - ]); - - $this->assertEquals($expectedJson, json_encode($content)); - } -} diff --git a/tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php b/tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php deleted file mode 100644 index 875b8bb7..00000000 --- a/tests/Identity/Extension/LocationConstraintExtensionBuilderTest.php +++ /dev/null @@ -1,164 +0,0 @@ -expectException(\RangeException::class); - $this->expectExceptionMessage('\'latitude\' value \'-91\' is less than \'-90\''); - - (new LocationConstraintExtensionBuilder()) - ->withLatitude(-91) - ->withLongitude(0) - ->build(); - } - - /** - * @covers ::withLatitude - */ - public function testLatitudeTooHigh() - { - $this->expectException(\RangeException::class); - $this->expectExceptionMessage('\'latitude\' value \'91\' is greater than \'90\''); - - (new LocationConstraintExtensionBuilder()) - ->withLatitude(91) - ->withLongitude(0) - ->build(); - } - - /** - * @covers ::withLongitude - */ - public function testLongitudeTooLow() - { - $this->expectException(\RangeException::class); - $this->expectExceptionMessage('\'longitude\' value \'-181\' is less than \'-180\''); - - (new LocationConstraintExtensionBuilder()) - ->withLatitude(0) - ->withLongitude(-181) - ->build(); - } - - /** - * @covers ::withLongitude - */ - public function testLongitudeTooHigh() - { - $this->expectException(\RangeException::class); - $this->expectExceptionMessage('\'longitude\' value \'181\' is greater than \'180\''); - - (new LocationConstraintExtensionBuilder()) - ->withLatitude(0) - ->withLongitude(181) - ->build(); - } - - /** - * @covers ::withRadius - */ - public function testRadiusLessThanZero() - { - $this->expectException(\RangeException::class); - $this->expectExceptionMessage('\'radius\' value \'-1\' is less than \'0\''); - - (new LocationConstraintExtensionBuilder()) - ->withLatitude(0) - ->withLongitude(0) - ->withRadius(-1) - ->build(); - } - - /** - * @covers ::withMaxUncertainty - */ - public function testMaxUncertaintyLessThanZero() - { - $this->expectException(\RangeException::class); - $this->expectExceptionMessage('\'maxUncertainty\' value \'-1\' is less than \'0\''); - - (new LocationConstraintExtensionBuilder()) - ->withLatitude(0) - ->withLongitude(0) - ->withMaxUncertainty(-1) - ->build(); - } - - /** - * @covers ::build - */ - public function testBuild() - { - $expectedLatitude = 50.8169; - $expectedLongitude = -0.1367; - $expectedRadius = 30; - $expectedMaxUncertainty = 40; - - $extension = (new LocationConstraintExtensionBuilder()) - ->withLatitude($expectedLatitude) - ->withLongitude($expectedLongitude) - ->withRadius($expectedRadius) - ->withMaxUncertainty($expectedMaxUncertainty) - ->build(); - - $expectedJson = json_encode([ - 'type' => self::TYPE_LOCATION_CONSTRAINT, - 'content' => [ - 'expected_device_location' => [ - 'latitude' => $expectedLatitude, - 'longitude' => $expectedLongitude, - 'radius' => $expectedRadius, - 'max_uncertainty_radius' => $expectedMaxUncertainty, - ], - ], - ]); - - $this->assertEquals($expectedJson, json_encode($extension)); - } - - /** - * @covers ::build - */ - public function testBuildDefaultValues() - { - $expectedLatitude = 50.8169; - $expectedLongitude = -0.1367; - $expectedDefaultRadius = 150; - $expectedDefaultMaxUncertainty = 150; - - $extension = (new LocationConstraintExtensionBuilder()) - ->withLatitude($expectedLatitude) - ->withLongitude($expectedLongitude) - ->build(); - - $expectedJson = json_encode([ - 'type' => self::TYPE_LOCATION_CONSTRAINT, - 'content' => [ - 'expected_device_location' => [ - 'latitude' => $expectedLatitude, - 'longitude' => $expectedLongitude, - 'radius' => $expectedDefaultRadius, - 'max_uncertainty_radius' => $expectedDefaultMaxUncertainty, - ], - ], - ]); - - $this->assertEquals($expectedJson, json_encode($extension)); - } -} diff --git a/tests/Identity/Extension/ThirdPartyAttributeContentTest.php b/tests/Identity/Extension/ThirdPartyAttributeContentTest.php deleted file mode 100644 index 4fe6b729..00000000 --- a/tests/Identity/Extension/ThirdPartyAttributeContentTest.php +++ /dev/null @@ -1,42 +0,0 @@ - '2019-12-02T12:00:00.123+00:00', - 'definitions' => [ - [ - 'name' => $someDefinition, - ], - ], - ]); - - $this->assertEquals($expectedJson, json_encode($thirdPartyAttributeContent)); - } -} diff --git a/tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php b/tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php deleted file mode 100644 index 43252040..00000000 --- a/tests/Identity/Extension/ThirdPartyAttributeExtensionBuilderTest.php +++ /dev/null @@ -1,132 +0,0 @@ -someDate = new \DateTime(self::SOME_DATE_STRING); - } - - /** - * @covers ::withExpiryDate - * @covers ::withDefinition - * @covers ::build - */ - public function testBuild() - { - $thirdPartyAttributeExtension = (new ThirdPartyAttributeExtensionBuilder()) - ->withExpiryDate($this->someDate) - ->withDefinition(self::SOME_DEFINITION) - ->withDefinition(self::SOME_OTHER_DEFINITION) - ->build(); - - $expectedJson = $this->createExpectedJson( - $this->someDate->format(\DateTime::RFC3339_EXTENDED), - [ - self::SOME_DEFINITION, - self::SOME_OTHER_DEFINITION, - ] - ); - - $this->assertJsonStringEqualsJsonString( - $expectedJson, - json_encode($thirdPartyAttributeExtension) - ); - } - - /** - * @covers ::withDefinitions - */ - public function testWithDefinitionsOverwritesExistingDefinitions() - { - $thirdPartyAttributeExtension = (new ThirdPartyAttributeExtensionBuilder()) - ->withExpiryDate($this->someDate) - ->withDefinition('initial definition') - ->withDefinitions([ - self::SOME_DEFINITION, - self::SOME_OTHER_DEFINITION, - ]) - ->build(); - - $this->assertJsonStringEqualsJsonString( - $this->createExpectedJson( - $this->someDate->format(\DateTime::RFC3339_EXTENDED), - [ - self::SOME_DEFINITION, - self::SOME_OTHER_DEFINITION, - ] - ), - json_encode($thirdPartyAttributeExtension) - ); - } - - /** - * @covers ::withExpiryDate - * - * @dataProvider expiryDateDataProvider - */ - public function testWithExpiryDateFormat($inputDate, $outputDate) - { - $thirdPartyAttributeExtension = (new ThirdPartyAttributeExtensionBuilder()) - ->withExpiryDate(new \DateTime($inputDate)) - ->build(); - - $this->assertJsonStringEqualsJsonString( - $this->createExpectedJson($outputDate, []), - json_encode($thirdPartyAttributeExtension) - ); - } - - /** - * Provides test expiry dates. - */ - public function expiryDateDataProvider(): array - { - return [ - ['2020-01-02T01:02:03.123456Z', '2020-01-02T01:02:03.123+00:00'], - ['2020-01-01T01:02:03.123+04:00', '2019-12-31T21:02:03.123+00:00'], - ['2020-01-02T01:02:03.123-02:00', '2020-01-02T03:02:03.123+00:00'] - ]; - } - - /** - * Create expected third party extension JSON. - * - * @param string $expiryDate - * @param string[] $definitions - * - * @return string - */ - private function createExpectedJson(string $expiryDate, array $definitions): string - { - return json_encode([ - 'type' => self::THIRD_PARTY_ATTRIBUTE_TYPE, - 'content' => [ - 'expiry_date' => $expiryDate, - 'definitions' => array_map( - function ($definition) { - return [ 'name' => $definition ]; - }, - $definitions - ), - ], - ]); - } -} diff --git a/tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php b/tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php deleted file mode 100644 index 6ad50610..00000000 --- a/tests/Identity/Extension/TransactionalFlowExtensionBuilderTest.php +++ /dev/null @@ -1,36 +0,0 @@ - 'content']; - - $constraints = (new TransactionalFlowExtensionBuilder()) - ->withContent($someContent) - ->build(); - - $expectedJson = json_encode([ - 'type' => self::TYPE_TRANSACTIONAL_FLOW, - 'content' => $someContent, - ]); - - $this->assertEquals($expectedJson, json_encode($constraints)); - } -} diff --git a/tests/Identity/IdentityServiceTest.php b/tests/Identity/IdentityServiceTest.php deleted file mode 100644 index 98b3cc08..00000000 --- a/tests/Identity/IdentityServiceTest.php +++ /dev/null @@ -1,133 +0,0 @@ -extensionMock = $this->createMock(Extension::class); - $this->policyMock = $this->createMock(Policy::class); - } - - /** - * @covers ::createShareSession - * @covers ::__construct - */ - public function testShouldCreateShareSession() - { - $shareSessionRequest = (new ShareSessionRequestBuilder()) - ->withPolicy($this->policyMock) - ->withRedirectUri(self::URI) - ->withExtension($this->extensionMock) - ->build(); - - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'some_id', - 'status' => 'some_status', - 'expiry' => 'some_time', - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $identityService = $this->createMock(IdentityService::class); - - $result = $identityService->createShareSession($shareSessionRequest); - - $this->assertInstanceOf(ShareSessionCreated::class, $result); - } - - /** - * @covers ::createShareQrCode - * @covers ::__construct - */ - public function testShouldCreateShareQrCode() - { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'some_id', - 'uri' => 'some_uri', - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $identityService = $this->createMock(IdentityService::class); - - $result = $identityService->createShareQrCode(TestData::SOME_ID); - - $this->assertInstanceOf(ShareSessionCreatedQrCode::class, $result); - } - - /** - * @covers ::fetchShareQrCode - * @covers ::__construct - */ - public function testShouldFetchShareQrCode() - { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'id', - 'expiry' => 'expiry', - 'policy' => 'policy', - 'extensions' => [['type' => 'type', 'content' => 'content']], - 'session' => ['id' => 'id', 'status' => 'status', 'expiry' => 'expiry'], - 'redirectUri' => 'redirectUri', - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $identityService = $this->createMock(IdentityService::class); - - $result = $identityService->fetchShareQrCode(TestData::SOME_ID); - - $this->assertInstanceOf(ShareSessionFetchedQrCode::class, $result); - } - - /** - * @covers ::fetchShareSession - * @covers ::__construct - */ - public function testShouldFetchShareSession() - { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'SOME_ID', - 'status' => 'SOME_STATUS', - 'expiry' => 'SOME_EXPIRY', - 'created' => 'SOME_CREATED', - 'updated' => 'SOME_UPDATED', - 'qrCode' => ['id' => 'SOME_QRCODE_ID'], - 'receipt' => ['id' => 'SOME_RECEIPT_ID'], - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $identityService = $this->createMock(IdentityService::class); - - $result = $identityService->fetchShareSession(TestData::SOME_ID); - - $this->assertInstanceOf(ShareSessionFetched::class, $result); - } -} diff --git a/tests/Identity/Policy/PolicyBuilderTest.php b/tests/Identity/Policy/PolicyBuilderTest.php deleted file mode 100644 index d223bd79..00000000 --- a/tests/Identity/Policy/PolicyBuilderTest.php +++ /dev/null @@ -1,644 +0,0 @@ -withFamilyName() - ->withGivenNames() - ->withFullName() - ->withDateOfBirth() - ->withGender() - ->withPostalAddress() - ->withStructuredPostalAddress() - ->withNationality() - ->withPhoneNumber() - ->withSelfie() - ->withEmail() - ->withDocumentDetails() - ->withDocumentImages() - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - ['name' => 'family_name', 'optional' => false], - ['name' => 'given_names', 'optional' => false], - ['name' => 'full_name', 'optional' => false], - ['name' => 'date_of_birth', 'optional' => false], - ['name' => 'gender', 'optional' => false], - ['name' => 'postal_address', 'optional' => false], - ['name' => 'structured_postal_address', 'optional' => false], - ['name' => 'nationality', 'optional' => false], - ['name' => 'phone_number', 'optional' => false], - ['name' => 'selfie', 'optional' => false], - ['name' => 'email_address', 'optional' => false], - ['name' => 'document_details', 'optional' => false], - ['name' => 'document_images', 'optional' => false], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withWantedAttributeByName - */ - public function testWithWantedAttributeByNameWithConstraints() - { - $someAttributeName = 'some_attribute_name'; - $sourceConstraint = (new SourceConstraintBuilder()) - ->withWantedAnchor(new WantedAnchor('SOME')) - ->build(); - - $constraints = [ - $sourceConstraint, - ]; - - $policy = (new PolicyBuilder()) - ->withWantedAttributeByName($someAttributeName, $constraints, true) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - [ - 'name' => $someAttributeName, - 'optional' => false, - "constraints" => [ - [ - "type" => "SOURCE", - "preferred_sources" => [ - "anchors" => [ - [ - "name" => "SOME", - "sub_type" => "", - ] - ], - "soft_preference" => false, - ], - ], - ], - "accept_self_asserted" => true, - ], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertJsonStringEqualsJsonString( - json_encode($expectedWantedAttributeData), - json_encode($policy) - ); - } - - /** - * @covers ::withWantedAttribute - * @covers ::withFamilyName - */ - public function testWithDuplicateAttribute() - { - $policy = (new PolicyBuilder()) - ->withFamilyName() - ->withFamilyName() - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - ['name' => 'family_name', 'optional' => false], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withWantedAttribute - * @covers ::withFamilyName - */ - public function testWithDuplicateAttributeDifferentConstraints() - { - $sourceConstraint = (new SourceConstraintBuilder()) - ->withWantedAnchor(new WantedAnchor('SOME')) - ->build(); - - $sourceConstraint2 = (new SourceConstraintBuilder()) - ->withWantedAnchor(new WantedAnchor('SOME_2')) - ->build(); - - - $policy = (new PolicyBuilder()) - ->withFamilyName() - ->withFamilyName([$sourceConstraint]) - ->withFamilyName([$sourceConstraint2]) - ->build(); - - $jsonData = $policy->jsonSerialize(); - - $this->assertCount(3, $jsonData->wanted); - foreach ($jsonData->wanted as $wantedAttribute) { - $this->assertEquals('family_name', $wantedAttribute->getName()); - } - } - - /** - * @covers ::build - * @covers ::withWantedAttributeByName - */ - public function testWithWantedAttributeByName() - { - $policy = (new PolicyBuilder()) - ->withWantedAttributeByName('family_name') - ->withWantedAttributeByName('given_names') - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - ['name' => 'family_name', 'optional' => false], - ['name' => 'given_names', 'optional' => false], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::build - * @covers ::withWantedAttribute - */ - public function testWithAttributeObjects() - { - $wantedFamilyName = (new WantedAttributeBuilder()) - ->withName('family_name') - ->build(); - - $wantedGivenNames = (new WantedAttributeBuilder()) - ->withName('given_names') - ->build(); - - $policy = (new PolicyBuilder()) - ->withWantedAttribute($wantedFamilyName) - ->withWantedAttribute($wantedGivenNames) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - ['name' => 'family_name', 'optional' => false], - ['name' => 'given_names', 'optional' => false], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withDateOfBirth - * @covers ::withAgeOver - * @covers ::withAgeUnder - * @covers ::withAgeDerivedAttribute - */ - public function testWithAgeDerivedAttributes() - { - $policy = (new PolicyBuilder()) - ->withDateOfBirth() - ->withAgeOver(18) - ->withAgeUnder(30) - ->withAgeUnder(40) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - ['name' => 'date_of_birth', 'optional' => false], - ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_over:18'], - ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_under:30'], - ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_under:40'], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withAgeDerivedAttribute - */ - public function testWithAgeDerivedAttributesWithConstraints() - { - $sourceConstraint = (new SourceConstraintBuilder()) - ->withWantedAnchor(new WantedAnchor('SOME')) - ->build(); - - - $policy = (new PolicyBuilder()) - ->withAgeDerivedAttribute(UserProfile::AGE_OVER . '18', [$sourceConstraint]) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - [ - 'name' => 'date_of_birth', - 'optional' => false, - 'derivation' => 'age_over:18', - "constraints" => [ - [ - "type" => "SOURCE", - "preferred_sources" => [ - "anchors" => [ - [ - "name" => "SOME", - "sub_type" => "", - ] - ], - "soft_preference" => false, - ], - ], - ], - ], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertJsonStringEqualsJsonString( - json_encode($expectedWantedAttributeData), - json_encode($policy) - ); - } - - - /** - * @covers ::withAgeUnder - * @covers ::withAgeDerivedAttribute - * @covers ::withWantedAttribute - */ - public function testWithDuplicateAgeDerivedAttributes() - { - $policy = (new PolicyBuilder()) - ->withAgeUnder(30) - ->withAgeUnder(30) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [ - ['name' => 'date_of_birth', 'optional' => false, 'derivation' => 'age_under:30'], - ], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - * @covers ::withPinAuthentication - * @covers ::withWantedAuthType - */ - public function testWithAuthTypes() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication() - ->withPinAuthentication() - ->withWantedAuthType(99) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE, 99], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - * @covers ::withPinAuthentication - * @covers ::withWantedAuthType - */ - public function testWithAuthTypesTrue() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication() - ->withPinAuthentication() - ->withWantedAuthType(99) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE, 99], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - * @covers ::withPinAuthentication - * @covers ::withWantedAuthType - */ - public function testWithAuthTypesFalse() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication(false) - ->withPinAuthentication(false) - ->withWantedAuthType(99, false) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - * @covers ::withPinAuthentication - */ - public function testWithAuthEnabledThenDisabled() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication() - ->withSelfieAuthentication(false) - ->withPinAuthentication() - ->withPinAuthentication(false) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - */ - public function testWithSameAuthTypeAddedOnlyOnce() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication() - ->withSelfieAuthentication() - ->withSelfieAuthentication() - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - */ - public function testWithOnlyTwoAuthTypes() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication() - ->withPinAuthentication() - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - */ - public function testWithNoSelfieAuthAfterRemoval() - { - $policy = (new PolicyBuilder()) - ->withSelfieAuthentication() - ->withSelfieAuthentication(false) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withSelfieAuthentication - */ - public function testWithNoPinAuthAfterRemoval() - { - $policy = (new PolicyBuilder()) - ->withPinAuthentication() - ->withPinAuthentication(false) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - - /** - * @covers ::withWantedRememberMe - */ - public function testWithRememberMe() - { - $policy = (new PolicyBuilder()) - ->withWantedRememberMe(true) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => true, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withWantedRememberMe - */ - public function testWithoutRememberMe() - { - $policy = (new PolicyBuilder()) - ->withWantedRememberMe(false) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withWantedRememberMeOptional - */ - public function testWithRememberMeOptional() - { - $policy = (new PolicyBuilder()) - ->withWantedRememberMeOptional(true) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => true, - 'identity_profile_requirements' => null, - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withWantedRememberMeOptional - */ - public function testWithoutRememberMeOptional() - { - $policy = (new PolicyBuilder()) - ->withWantedRememberMeOptional(false) - ->build(); - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null - ]; - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - } - - /** - * @covers ::withIdentityProfileRequirements - * @covers \Yoti\Identity\Policy\Policy::__construct - * @covers \Yoti\Identity\Policy\Policy::getIdentityProfileRequirements - * @covers \Yoti\Identity\Policy\Policy::jsonSerialize - */ - public function testWithIdentityProfileRequirements() - { - $identityProfileSample = (object)[ - 'trust_framework' => 'UK_TFIDA', - 'scheme' => [ - 'type' => 'DBS', - 'objective' => 'STANDARD' - ] - ]; - - $expectedWantedAttributeData = [ - 'wanted' => [], - 'wanted_auth_types' => [], - 'wanted_remember_me' => false, - 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => $identityProfileSample - ]; - - $policy = (new PolicyBuilder()) - ->withIdentityProfileRequirements($identityProfileSample) - ->build(); - - $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); - $this->assertEquals($identityProfileSample, $policy->getIdentityProfileRequirements()); - } -} diff --git a/tests/Identity/Policy/WantedAnchorBuilderTest.php b/tests/Identity/Policy/WantedAnchorBuilderTest.php deleted file mode 100644 index 2d0479e0..00000000 --- a/tests/Identity/Policy/WantedAnchorBuilderTest.php +++ /dev/null @@ -1,39 +0,0 @@ -withValue($someName) - ->withSubType($someSubType) - ->build(); - - $expectedJsonData = [ - 'name' => $someName, - 'sub_type' => $someSubType, - ]; - - $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAnchor)); - } -} diff --git a/tests/Identity/Policy/WantedAttributeBuilderTest.php b/tests/Identity/Policy/WantedAttributeBuilderTest.php deleted file mode 100644 index 7cd8a8f1..00000000 --- a/tests/Identity/Policy/WantedAttributeBuilderTest.php +++ /dev/null @@ -1,162 +0,0 @@ -withWantedAnchor(new WantedAnchor('SOME')) - ->build(); - - $wantedAttribute = (new WantedAttributeBuilder()) - ->withName($someName) - ->withDerivation($someDerivation) - ->withOptional(true) - ->withConstraint($sourceConstraint) - ->withAcceptSelfAsserted(false) - ->build(); - - $expectedJsonData = [ - 'name' => $someName, - 'optional' => true, - 'derivation' => $someDerivation, - 'constraints' => [$sourceConstraint], - 'accept_self_asserted' => false, - ]; - - $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttribute)); - $this->assertTrue($wantedAttribute->getOptional()); - $this->assertContains($sourceConstraint, $wantedAttribute->getConstraints()); - $this->assertFalse($wantedAttribute->getAcceptSelfAsserted()); - } - - /** - * @covers ::build - * @covers ::withName - */ - public function testEmptyName() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('name cannot be empty'); - - (new WantedAttributeBuilder()) - ->withName('') - ->build(); - } - - /** - * @covers ::withAcceptSelfAsserted - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::__construct - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::jsonSerialize - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::getAcceptSelfAsserted - */ - public function testAcceptSelfAsserted() - { - $someName = 'some name'; - - $expectedJsonData = [ - 'name' => $someName, - 'optional' => false, - 'accept_self_asserted' => true, - ]; - - $wantedAttributeDefault = (new WantedAttributeBuilder()) - ->withName($someName) - ->withAcceptSelfAsserted(true) - ->build(); - - $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttributeDefault)); - - $wantedAttribute = (new WantedAttributeBuilder()) - ->withName($someName) - ->withAcceptSelfAsserted(true) - ->build(); - - $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttribute)); - } - - /** - * @covers ::withAcceptSelfAsserted - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::__construct - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::jsonSerialize - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::getAcceptSelfAsserted - */ - public function testWithoutAcceptSelfAsserted() - { - $someName = 'some name'; - - $expectedJsonData = [ - 'name' => $someName, - 'optional' => false, - 'accept_self_asserted' => false, - ]; - - $wantedAttribute = (new WantedAttributeBuilder()) - ->withName($someName) - ->withAcceptSelfAsserted(false) - ->build(); - - $this->assertEquals(json_encode($expectedJsonData), json_encode($wantedAttribute)); - } - - /** - * @covers ::withAcceptSelfAsserted - * @covers ::withConstraints - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::__construct - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::jsonSerialize - * @covers \Yoti\ShareUrl\Policy\WantedAttribute::getAcceptSelfAsserted - */ - public function testWithMultipleConstraints() - { - $sourceConstraint = (new SourceConstraintBuilder()) - ->withWantedAnchor(new WantedAnchor('SOME')) - ->build(); - - $sourceConstraint2 = (new SourceConstraintBuilder()) - ->withWantedAnchor(new WantedAnchor('SOME_2')) - ->build(); - - - $constraints = [ - $sourceConstraint, - $sourceConstraint2 - ]; - - $wantedAttribute = (new WantedAttributeBuilder()) - ->withName('someName') - ->withAcceptSelfAsserted(false) - ->withConstraints($constraints) - ->build(); - - $this->assertEquals($constraints, $wantedAttribute->getConstraints()); - } -} diff --git a/tests/Identity/ShareSessionCreatedQrCodeTest.php b/tests/Identity/ShareSessionCreatedQrCodeTest.php deleted file mode 100644 index c0fc50ba..00000000 --- a/tests/Identity/ShareSessionCreatedQrCodeTest.php +++ /dev/null @@ -1,42 +0,0 @@ - self::SOME_ID, - 'uri' => self::SOME_URI, - 'failed' => 'failed' - ]); - - $expected = [ - 'id' => self::SOME_ID, - 'uri' => self::SOME_URI, - ]; - - $this->assertInstanceOf(ShareSessionCreatedQrCode::class, $qrCode); - - $this->assertEquals(self::SOME_ID, $qrCode->getId()); - $this->assertEquals(self::SOME_URI, $qrCode->getUri()); - - $this->assertEquals(json_encode($expected), json_encode($qrCode)); - } -} diff --git a/tests/Identity/ShareSessionCreatedTest.php b/tests/Identity/ShareSessionCreatedTest.php deleted file mode 100644 index 380be268..00000000 --- a/tests/Identity/ShareSessionCreatedTest.php +++ /dev/null @@ -1,45 +0,0 @@ - self::SOME_ID, - 'status' => self::SOME_STATUS, - 'expiry' => self::SOME_EXPIRY, - 'failed' => 'SQL injection' - ]); - - $expected = [ - 'id' => self::SOME_ID, - 'status' => self::SOME_STATUS, - 'expiry' => self::SOME_EXPIRY, - ]; - - $this->assertInstanceOf(ShareSessionCreated::class, $shareSession); - $this->assertEquals(self::SOME_ID, $shareSession->getId()); - $this->assertEquals(self::SOME_STATUS, $shareSession->getStatus()); - $this->assertEquals(self::SOME_EXPIRY, $shareSession->getExpiry()); - $this->assertEquals(json_encode($expected), json_encode($shareSession)); - } -} diff --git a/tests/Identity/ShareSessionFetchedQrCodeTest.php b/tests/Identity/ShareSessionFetchedQrCodeTest.php deleted file mode 100644 index 3be47c69..00000000 --- a/tests/Identity/ShareSessionFetchedQrCodeTest.php +++ /dev/null @@ -1,76 +0,0 @@ - 'some', 'content' => 'content'], - ['type' => 'some2', 'content' => 'content2'], - ]; - - $shareSession = [ - 'id' => 'some', - 'status' => 'status', - 'expiry' => 'expiry', - ]; - - $qrCode = new ShareSessionFetchedQrCode([ - 'id' => self::SOME_ID, - 'expiry' => self::SOME_EXPIRY, - 'policy' => self::SOME_POLICY, - 'extensions' => $extensions, - 'session' => $shareSession, - 'redirectUri' => self::SOME_REDIRECT_URI, - ]); - - $expected = [ - 'id' => self::SOME_ID, - 'expiry' => self::SOME_EXPIRY, - 'policy' => self::SOME_POLICY, - 'extensions' => $extensions, - 'session' => $shareSession, - 'redirectUri' => self::SOME_REDIRECT_URI, - ]; - - $this->assertInstanceOf(ShareSessionFetchedQrCode::class, $qrCode); - - $this->assertEquals(self::SOME_ID, $qrCode->getId()); - $this->assertEquals(self::SOME_EXPIRY, $qrCode->getExpiry()); - $this->assertEquals(self::SOME_POLICY, $qrCode->getPolicy()); - $this->assertEquals(self::SOME_REDIRECT_URI, $qrCode->getRedirectUri()); - - $this->assertInstanceOf(ShareSessionCreated::class, $qrCode->getSession()); - - $this->assertContainsOnlyInstancesOf(Extension::class, $qrCode->getExtensions()); - - $this->assertEquals(self::SOME_REDIRECT_URI, $qrCode->getRedirectUri()); - - $this->assertEquals(json_encode($expected), json_encode($qrCode)); - } -} diff --git a/tests/Identity/ShareSessionFetchedTest.php b/tests/Identity/ShareSessionFetchedTest.php deleted file mode 100644 index cc38224d..00000000 --- a/tests/Identity/ShareSessionFetchedTest.php +++ /dev/null @@ -1,66 +0,0 @@ - self::SOME_ID, - 'status' => self::SOME_STATUS, - 'expiry' => self::SOME_EXPIRY, - 'created' => self::SOME_CREATED, - 'updated' => self::SOME_UPDATED, - 'failed' => 'SQL injection', - 'qrCode' => ['id' => self::SOME_QRCODE_ID], - 'receipt' => ['id' => self::SOME_RECEIPT_ID], - ]); - - $expected = [ - 'id' => self::SOME_ID, - 'status' => self::SOME_STATUS, - 'expiry' => self::SOME_EXPIRY, - 'created' => self::SOME_CREATED, - 'updated' => self::SOME_UPDATED, - 'qrCodeId' => self::SOME_QRCODE_ID, - 'receiptId' => self::SOME_RECEIPT_ID, - ]; - - $this->assertInstanceOf(ShareSessionFetched::class, $shareSession); - $this->assertEquals(self::SOME_ID, $shareSession->getId()); - $this->assertEquals(self::SOME_STATUS, $shareSession->getStatus()); - $this->assertEquals(self::SOME_EXPIRY, $shareSession->getExpiry()); - $this->assertEquals(self::SOME_CREATED, $shareSession->getCreated()); - $this->assertEquals(self::SOME_UPDATED, $shareSession->getUpdated()); - $this->assertEquals(self::SOME_QRCODE_ID, $shareSession->getQrCodeId()); - $this->assertEquals(self::SOME_RECEIPT_ID, $shareSession->getReceiptId()); - $this->assertEquals(json_encode($expected), json_encode($shareSession)); - } -} diff --git a/tests/Identity/ShareSessionNotificationBuilderTest.php b/tests/Identity/ShareSessionNotificationBuilderTest.php deleted file mode 100644 index ffee1e5e..00000000 --- a/tests/Identity/ShareSessionNotificationBuilderTest.php +++ /dev/null @@ -1,80 +0,0 @@ - 'auth', 'header_3' => 'auth_3']; - - /** - * @covers ::withUrl - * @covers ::withMethod - * @covers ::withHeader - * @covers ::withVerifyTls - * @covers ::build - * @covers \Yoti\Identity\ShareSessionNotification::getUrl - * @covers \Yoti\Identity\ShareSessionNotification::getHeaders - * @covers \Yoti\Identity\ShareSessionNotification::getMethod - * @covers \Yoti\Identity\ShareSessionNotification::getUrl - * @covers \Yoti\Identity\ShareSessionNotification::__construct - */ - public function testShouldBuildCorrectly() - { - $shareNotification = (new ShareSessionNotificationBuilder()) - ->withMethod() - ->withUrl(self::URL) - ->withHeader(self::HEADER_KEY, self::HEADER_VALUE) - ->withVerifyTls() - ->build(); - - $this->assertInstanceOf(ShareSessionNotification::class, $shareNotification); - - $this->assertEquals(self::URL, $shareNotification->getUrl()); - $this->assertEquals([self::HEADER_KEY => self::HEADER_VALUE], $shareNotification->getHeaders()); - $this->assertEquals('POST', $shareNotification->getMethod()); - } - - /** - * @covers ::withUrl - * @covers ::withMethod - * @covers ::withHeaders - * @covers ::withVerifyTls - * @covers ::build - * @covers \Yoti\Identity\ShareSessionNotification::getHeaders - * @covers \Yoti\Identity\ShareSessionNotification::isVerifyTls - * @covers \Yoti\Identity\ShareSessionNotification::jsonSerialize - * @covers \Yoti\Identity\ShareSessionNotification::__construct - */ - public function testShouldBuildCorrectlyWithMultipleHeaders() - { - $shareNotification = (new ShareSessionNotificationBuilder()) - ->withMethod() - ->withUrl(self::URL) - ->withHeaders(self::HEADERS) - ->withVerifyTls(false) - ->build(); - - $expected = [ - 'url' => self::URL, - 'method' => 'POST', - 'verifyTls' => false, - 'headers' => self::HEADERS, - ]; - - $this->assertEquals(self::HEADERS, $shareNotification->getHeaders()); - $this->assertFalse($shareNotification->isVerifyTls()); - $this->assertEquals(json_encode($expected), json_encode($shareNotification)); - } -} diff --git a/tests/Identity/ShareSessionRequestBuilderTest.php b/tests/Identity/ShareSessionRequestBuilderTest.php deleted file mode 100644 index 4be3a1ef..00000000 --- a/tests/Identity/ShareSessionRequestBuilderTest.php +++ /dev/null @@ -1,100 +0,0 @@ -extensionMock = $this->createMock(Extension::class); - $this->policyMock = $this->createMock(Policy::class); - } - - /** - * @covers ::withRedirectUri - * @covers ::withPolicy - * @covers ::withExtension - * @covers ::withNotification - * @covers ::withSubject - * @covers ::build - * @covers \Yoti\Identity\ShareSessionRequest::getPolicy - * @covers \Yoti\Identity\ShareSessionRequest::getNotification - * @covers \Yoti\Identity\ShareSessionRequest::getExtensions - * @covers \Yoti\Identity\ShareSessionRequest::getSubject - * @covers \Yoti\Identity\ShareSessionRequest::__construct - */ - public function testShouldBuildCorrectly() - { - $subject = [ - 'key' => (object)['some' => 'good'] - ]; - - $shareNotification = (new ShareSessionNotificationBuilder()) - ->withMethod() - ->withUrl('some') - ->withHeader('some', 'some') - ->withVerifyTls() - ->build(); - - $shareRequest = (new ShareSessionRequestBuilder()) - ->withSubject($subject) - ->withNotification($shareNotification) - ->withPolicy($this->policyMock) - ->withRedirectUri(self::URI) - ->withExtension($this->extensionMock) - ->build(); - - $this->assertInstanceOf(ShareSessionRequest::class, $shareRequest); - - $this->assertEquals($subject, $shareRequest->getSubject()); - $this->assertEquals([$this->extensionMock], $shareRequest->getExtensions()); - $this->assertEquals($this->policyMock, $shareRequest->getPolicy()); - $this->assertEquals($shareNotification, $shareRequest->getNotification()); - $this->assertEquals(self::URI, $shareRequest->getRedirectUri()); - } - - /** - * @covers ::withRedirectUri - * @covers ::withPolicy - * @covers ::withExtensions - * @covers ::withNotification - * @covers ::withSubject - * @covers ::build - * @covers \Yoti\Identity\ShareSessionRequest::getExtensions - * @covers \Yoti\Identity\ShareSessionRequest::__construct - * @covers \Yoti\Identity\ShareSessionRequest::jsonSerialize - */ - public function testShouldBuildCorrectlyWithMultipleExtensions() - { - $shareRequest = (new ShareSessionRequestBuilder()) - ->withPolicy($this->policyMock) - ->withRedirectUri(self::URI) - ->withExtensions([$this->extensionMock]) - ->build(); - - - $expected = [ - 'policy' => $this->policyMock, - 'redirectUri' => self::URI, - 'extensions' => [$this->extensionMock], - ]; - - $this->assertEquals([$this->extensionMock], $shareRequest->getExtensions()); - $this->assertEquals(json_encode($expected), json_encode($shareRequest)); - } -} diff --git a/tests/YotiClientTest.php b/tests/YotiClientTest.php index 828373ab..24ddaa36 100755 --- a/tests/YotiClientTest.php +++ b/tests/YotiClientTest.php @@ -13,12 +13,6 @@ use Yoti\Aml\Profile as AmlProfile; use Yoti\Aml\Result as AmlResult; use Yoti\Exception\DateTimeException; -use Yoti\Identity\Policy\Policy; -use Yoti\Identity\ShareSessionCreated; -use Yoti\Identity\ShareSessionCreatedQrCode; -use Yoti\Identity\ShareSessionFetched; -use Yoti\Identity\ShareSessionFetchedQrCode; -use Yoti\Identity\ShareSessionRequestBuilder; use Yoti\Profile\ActivityDetails; use Yoti\ShareUrl\DynamicScenarioBuilder; use Yoti\ShareUrl\Policy\DynamicPolicyBuilder; @@ -210,140 +204,6 @@ public function testCreateShareUrl() $this->assertInstanceOf(ShareUrlResult::class, $result); } - /** - * @covers ::createShareSession - * @covers ::__construct - */ - public function testCreateShareSession() - { - $policy = $this->createMock(Policy::class); - $redirectUri = 'https://host/redirect/'; - - $shareSessionRequest = (new ShareSessionRequestBuilder()) - ->withPolicy($policy) - ->withRedirectUri($redirectUri) - ->build(); - - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'some_id', - 'status' => 'some_status', - 'expiry' => 'some_time', - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient - ->expects($this->once()) - ->method('sendRequest') - ->willReturn($response); - - $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ - Config::HTTP_CLIENT => $httpClient, - ]); - - $result = $yotiClient->createShareSession($shareSessionRequest); - - $this->assertInstanceOf(ShareSessionCreated::class, $result); - } - - /** - * @covers ::createShareQrCode - * @covers ::__construct - */ - public function testCreateShareQrCode() - { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'some_id', - 'uri' => 'some_uri', - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient - ->expects($this->once()) - ->method('sendRequest') - ->willReturn($response); - - $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ - Config::HTTP_CLIENT => $httpClient, - ]); - - $result = $yotiClient->createShareQrCode(TestData::SOME_ID); - - $this->assertInstanceOf(ShareSessionCreatedQrCode::class, $result); - } - - /** - * @covers ::fetchShareQrCode - * @covers ::__construct - */ - public function testFetchShareQrCode() - { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'id', - 'expiry' => 'expiry', - 'policy' => 'policy', - 'extensions' => [['type' => 'type', 'content' => 'content']], - 'session' => ['id' => 'id', 'status' => 'status', 'expiry' => 'expiry'], - 'redirectUri' => 'redirectUri', - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient - ->expects($this->once()) - ->method('sendRequest') - ->willReturn($response); - - $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ - Config::HTTP_CLIENT => $httpClient, - ]); - - $result = $yotiClient->fetchShareQrCode(TestData::SOME_ID); - - $this->assertInstanceOf(ShareSessionFetchedQrCode::class, $result); - } - - /** - * @covers ::fetchShareSession - * @covers ::__construct - */ - public function testFetchShareSession() - { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody')->willReturn(Psr7\Utils::streamFor(json_encode([ - 'id' => 'SOME_ID', - 'status' => 'SOME_STATUS', - 'expiry' => 'SOME_EXPIRY', - 'created' => 'SOME_CREATED', - 'updated' => 'SOME_UPDATED', - 'qrCode' => ['id' => 'SOME_QRCODE_ID'], - 'receipt' => ['id' => 'SOME_RECEIPT_ID'], - ]))); - - $response->method('getStatusCode')->willReturn(201); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient - ->expects($this->once()) - ->method('sendRequest') - ->willReturn($response); - - $yotiClient = new YotiClient(TestData::SDK_ID, TestData::PEM_FILE, [ - Config::HTTP_CLIENT => $httpClient, - ]); - - $result = $yotiClient->fetchShareSession(TestData::SOME_ID); - - $this->assertInstanceOf(ShareSessionFetched::class, $result); - } - /** * @covers ::getLoginUrl */ From ad27c2a956b097010472434087218e1229cff0fe Mon Sep 17 00:00:00 2001 From: mehmet-yoti Date: Tue, 18 Jul 2023 15:11:33 +0100 Subject: [PATCH 19/19] version update for release --- composer.json | 2 +- src/Constants.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 602c2179..0af26520 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "yoti/yoti-php-sdk", "description": "Yoti SDK for quickly integrating your PHP backend with Yoti", - "version": "4.2.0", + "version": "4.2.1", "keywords": [ "yoti", "sdk" diff --git a/src/Constants.php b/src/Constants.php index f784e2ec..d8a8ceaa 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -25,7 +25,7 @@ class Constants public const SDK_IDENTIFIER = 'PHP'; /** Default SDK version */ - public const SDK_VERSION = '4.2.0'; + public const SDK_VERSION = '4.2.1'; /** Base url for connect page (user will be redirected to this page eg. baseurl/app-id) */ public const CONNECT_BASE_URL = 'https://www.yoti.com/connect';