Skip to content

Commit 376b3df

Browse files
committed
Testing complete
1 parent cdd11dd commit 376b3df

File tree

16 files changed

+346
-187
lines changed

16 files changed

+346
-187
lines changed

phpunit.xml.dist

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
<testsuite name="client">
2727
<directory>test/Client</directory>
2828
</testsuite>
29+
<testsuite name="sim_swap">
30+
<directory>test/SimSwap</directory>
31+
</testsuite>
32+
<testsuite name="number_verification">
33+
<directory>test/NumberVerification</directory>
34+
</testsuite>
2935
<testsuite name="conversations">
3036
<directory>test/Conversation</directory>
3137
</testsuite>

src/Client.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Vonage\Client\Credentials\Basic;
2525
use Vonage\Client\Credentials\Container;
2626
use Vonage\Client\Credentials\CredentialsInterface;
27+
use Vonage\Client\Credentials\Gnp;
2728
use Vonage\Client\Credentials\Handler\BasicHandler;
2829
use Vonage\Client\Credentials\Handler\SignatureBodyFormHandler;
2930
use Vonage\Client\Credentials\Handler\SignatureBodyHandler;
@@ -171,12 +172,12 @@ public function __construct(
171172

172173
$this->setHttpClient($client);
173174

174-
// Make sure we know how to use the credentials
175175
if (
176176
!($credentials instanceof Container) &&
177177
!($credentials instanceof Basic) &&
178178
!($credentials instanceof SignatureSecret) &&
179-
!($credentials instanceof Keypair)
179+
!($credentials instanceof Keypair) &&
180+
!($credentials instanceof Gnp)
180181
) {
181182
throw new RuntimeException('unknown credentials type: ' . $credentials::class);
182183
}

src/Client/APIResource.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public function addAuth(RequestInterface $request): RequestInterface
7575
$request = $handler($request, $credentials);
7676
break;
7777
} catch (\RuntimeException $e) {
78+
die($e->getMessage());
7879
continue; // We are OK if multiple are sent but only one match
7980
}
8081
throw new \RuntimeException(

src/Client/Credentials/Container.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class Container extends AbstractCredentials
1414
protected array $types = [
1515
Basic::class,
1616
SignatureSecret::class,
17-
Keypair::class
17+
Keypair::class,
18+
Gnp::class
1819
];
1920

2021
/**

src/Client/Credentials/Gnp.php

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@
44

55
namespace Vonage\Client\Credentials;
66

7-
class Gnp extends Keypair
7+
use Lcobucci\JWT\Encoding\JoseEncoder;
8+
use Lcobucci\JWT\Token;
9+
use Vonage\JWT\TokenGenerator;
10+
11+
class Gnp extends AbstractCredentials
812
{
913
protected ?string $code = null;
1014
protected ?string $state = null;
1115
protected ?string $redirectUri = null;
1216

13-
public function __construct(protected string $msisdn, protected string $key, $application = null)
17+
public function __construct(
18+
protected string $msisdn,
19+
protected string $key,
20+
protected $application = null
21+
) {
22+
}
23+
24+
public function getKeyRaw(): string
1425
{
15-
parent::__construct($key, $application);
26+
return $this->key;
1627
}
1728

1829
public function getMsisdn(): string
@@ -59,4 +70,62 @@ public function setRedirectUri(?string $redirectUri): Gnp
5970
$this->redirectUri = $redirectUri;
6071
return $this;
6172
}
73+
74+
public function generateJwt(array $claims = []): Token
75+
{
76+
$generator = new TokenGenerator($this->application, $this->getKeyRaw());
77+
78+
if (isset($claims['exp'])) {
79+
// This will change to an Exception in 5.0
80+
trigger_error('Expiry date is automatically generated from now and TTL, so cannot be passed in
81+
as an argument in claims', E_USER_WARNING);
82+
unset($claims['nbf']);
83+
}
84+
85+
if (isset($claims['ttl'])) {
86+
$generator->setTTL($claims['ttl']);
87+
unset($claims['ttl']);
88+
}
89+
90+
if (isset($claims['jti'])) {
91+
$generator->setJTI($claims['jti']);
92+
unset($claims['jti']);
93+
}
94+
95+
if (isset($claims['nbf'])) {
96+
// Due to older versions of lcobucci/jwt, this claim has
97+
// historic fraction conversation issues. For now, nbf is not supported.
98+
// This will change to an Exception in 5.0
99+
trigger_error('NotBefore Claim is not supported in Vonage JWT', E_USER_WARNING);
100+
unset($claims['nbf']);
101+
}
102+
103+
if (isset($claims['sub'])) {
104+
$generator->setSubject($claims['sub']);
105+
unset($claims['sub']);
106+
}
107+
108+
if (!empty($claims)) {
109+
foreach ($claims as $claim => $value) {
110+
$generator->addClaim($claim, $value);
111+
}
112+
}
113+
114+
$jwt = $generator->generate();
115+
$parser = new Token\Parser(new JoseEncoder());
116+
117+
// Backwards compatible for signature. In 5.0 this will return a string value
118+
return $parser->parse($jwt);
119+
}
120+
121+
public function getApplication(): ?string
122+
{
123+
return $this->application;
124+
}
125+
126+
public function setApplication(mixed $application): Keypair
127+
{
128+
$this->application = $application;
129+
return $this;
130+
}
62131
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Vonage\Client\Credentials\Handler;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
use Vonage\Client\Credentials\CredentialsInterface;
7+
use Vonage\Client\Credentials\Gnp;
8+
use Vonage\Client\Credentials\Keypair;
9+
10+
class GnpKeypairHandler extends AbstractHandler
11+
{
12+
public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface
13+
{
14+
/** @var Keypair $credentials */
15+
$credentials = $this->extract(Gnp::class, $credentials);
16+
$token = $credentials->generateJwt();
17+
18+
return $request->withHeader('Authorization', 'Bearer ' . $token->toString());
19+
}
20+
}

src/Client/Credentials/Handler/NumberVerificationGnpHandler.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,19 @@ public function __invoke(RequestInterface $request, CredentialsInterface $creden
4848

4949
// submit the code to CAMARA endpoint
5050
$api = new APIResource();
51-
$api->setAuthHandlers(new KeypairHandler());
51+
$api->setAuthHandlers(new GnpKeypairHandler());
5252
$api->setClient($this->getClient());
5353
$api->setBaseUrl('https://api-eu.vonage.com/oauth2/token');
5454

55-
$tokenRequest = $api->submit([
55+
$tokenResponse = $api->submit([
5656
'grant_type' => 'authorization_code',
5757
'code' => $credentials->getCode(),
5858
'redirect_uri' => $credentials->getRedirectUri()
5959
]);
6060

61-
$token = $tokenRequest['access_token'];
61+
$payload = json_decode($tokenResponse, true);
6262

6363
// Add CAMARA Access Token to request and return to make API call
64-
return $request->withHeader('Authorization', 'Bearer ' . $token);
64+
return $request->withHeader('Authorization', 'Bearer ' . $payload['access_token']);
6565
}
6666
}

src/Client/Credentials/Handler/SimSwapGnpHandler.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,19 @@ public function setTokenUrl(?string $tokenUrl): SimSwapGnpHandler
4141
return $this;
4242
}
4343

44+
public string $token;
45+
4446
public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface
4547
{
4648
/** @var Gnp $credentials */
4749
$credentials = $this->extract(Gnp::class, $credentials);
4850
$msisdn = $credentials->getMsisdn();
4951

50-
// Request OIDC, returns Auth Request ID
51-
// Reconfigure new client for GNP Auth
5252
$api = new APIResource();
53-
$api->setAuthHandlers(new KeypairHandler());
53+
$api->setAuthHandlers(new GnpKeypairHandler());
5454
$api->setClient($this->getClient());
5555
$api->setBaseUrl($this->getBaseUrl());
5656

57-
// This handler requires an injected client configured with a Gnp credentials object and a configured scope
5857
$response = $api->submit([
5958
'login_hint' => $msisdn,
6059
'scope' => $this->getScope()

src/NumberVerification/Client.php

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
namespace Vonage\NumberVerification;
66

7-
use GuzzleHttp\Psr7\Request;
87
use Psr\Http\Client\ClientExceptionInterface;
98
use Vonage\Client\APIClient;
109
use Vonage\Client\APIResource;
10+
use Vonage\Client\Credentials\Container;
1111
use Vonage\Client\Credentials\CredentialsInterface;
1212
use Vonage\Client\Credentials\Gnp;
1313
use Vonage\Client\Exception\Credentials;
@@ -34,36 +34,36 @@ public function getAPIResource(): APIResource
3434
* @throws ClientExceptionInterface
3535
* @throws Exception
3636
*/
37-
public function verifyNumber(string $phoneNumber): bool
37+
public function verifyNumber(string $phoneNumber, string $code, string $state): bool
3838
{
39-
$webhook = Factory::createFromGlobals();
40-
41-
if (!isset($webhook['code'])) {
42-
throw new Exception('Required field code not found in webhook');
43-
};
44-
4539
/** @var Gnp $credentials */
4640
$credentials = $this->getAPIResource()->getClient()->getCredentials();
47-
$credentials->setCode($webhook['code']);
48-
$credentials->setState($webhook['state']);
41+
42+
if ($credentials instanceof Container) {
43+
$credentials = $credentials->get(Gnp::class);
44+
}
45+
46+
$credentials->setCode($code);
4947

5048
$phoneNumberKey = 'phoneNumber';
5149

5250
if ($this->isHashedPhoneNumber($phoneNumber)) {
5351
$phoneNumberKey = 'hashedPhoneNumber';
5452
}
5553

56-
// This request will now contain a valid CAMARA token
57-
$response = $this->getAPIResource()->create([
58-
$phoneNumberKey => $phoneNumber
59-
]);
54+
// By the time this hits Number Verification, the handler will have
55+
// completed the OAuth flow
56+
$response = $this->getAPIResource()->create(
57+
[$phoneNumberKey => $phoneNumber],
58+
'verify'
59+
);
6060

6161
return $response['devicePhoneNumberVerified'];
6262
}
6363

6464
public function isHashedPhoneNumber(string $phoneNumber): bool
6565
{
66-
return (strlen($phoneNumber) >= 13);
66+
return (strlen($phoneNumber) >= 15);
6767
}
6868

6969
/**
@@ -80,6 +80,11 @@ public function buildFrontEndUrl(string $phoneNumber, string $redirectUrl, strin
8080
{
8181
/** @var Gnp $credentials */
8282
$credentials = $this->getAPIResource()->getClient()->getCredentials();
83+
84+
if ($credentials instanceof Container) {
85+
$credentials = $credentials->get(Gnp::class);
86+
}
87+
8388
$this->enforceCredentials($credentials);
8489

8590
$applicationId = $credentials->getApplication();

src/SimSwap/Client.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public function getAPIResource(): APIResource
1919
return $this->api;
2020
}
2121

22-
2322
public function checkSimSwap(string $number, ?int $maxAge = null)
2423
{
2524
/** @var SimSwapGnpHandler $handler */
@@ -29,8 +28,6 @@ public function checkSimSwap(string $number, ?int $maxAge = null)
2928
throw new \RuntimeException('SimSwap Client has been misconfigured. Only a GNP Handler can be used');
3029
}
3130

32-
$handler->setScope('dpv:FraudPreventionAndDetection#check-sim-swap');
33-
3431
$payload = [
3532
'phoneNumber' => $number
3633
];
@@ -53,7 +50,7 @@ public function checkSimSwapDate(string $number): string
5350
throw new \RuntimeException('SimSwap Client has been misconfigured. Only a GNP Handler can be used');
5451
}
5552

56-
$handler->setScope('dpv:FraudPreventionAndDetection#retrieve-sim-swap');
53+
$handler->setScope('dpv:FraudPreventionAndDetection#retrieve-sim-swap-date');
5754

5855
$response = $this->getAPIResource()->create(['phoneNumber' => $number], 'retrieve-date');
5956

0 commit comments

Comments
 (0)