Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ac6f6d2
First stage refactor CredentitalManagers
JamesFreeman Sep 10, 2024
0d57219
migrate to new dataproviders for credentialmanagers
JamesFreeman Sep 11, 2024
9246eda
Apply fixes from StyleCI
StyleCIBot Sep 11, 2024
127ba8e
Merge pull request #1 from JamesFreeman/analysis-GP5732
JamesFreeman Sep 11, 2024
ffd6622
revert big bc, change session key for cache store
JamesFreeman Sep 11, 2024
523817c
revert big bc, change session key for cache store
JamesFreeman Sep 11, 2024
b118b93
Adding new Model based storage
JamesFreeman Sep 12, 2024
1fe7600
revert
JamesFreeman Sep 12, 2024
8a9b2d6
refactor
JamesFreeman Sep 12, 2024
f4375a3
Apply fixes from StyleCI
StyleCIBot Sep 12, 2024
242da4e
Merge pull request #2 from JamesFreeman/analysis-BoJQRV
JamesFreeman Sep 12, 2024
c80178d
first pass
JamesFreeman Sep 13, 2024
7c31876
fix tests
JamesFreeman Sep 14, 2024
29755fc
remove config tests
JamesFreeman Sep 14, 2024
e177fe4
Apply fixes from StyleCI
StyleCIBot Sep 14, 2024
13c3610
Merge pull request #3 from JamesFreeman/analysis-4wPZYk
JamesFreeman Sep 14, 2024
00a9c68
New exceptions, changes to how constructors work.
JamesFreeman Oct 5, 2024
82d2f42
Apply fixes from StyleCI
StyleCIBot Oct 5, 2024
04b5162
Merge pull request #4 from JamesFreeman/analysis-RPNmjD
JamesFreeman Oct 5, 2024
d43db97
change tests
JamesFreeman Oct 5, 2024
ca04e09
Merge branch 'feature/new-credential-managers' of github.com:JamesFre…
JamesFreeman Oct 5, 2024
8329355
Apply fixes from StyleCI
StyleCIBot Oct 5, 2024
70142b1
Merge pull request #5 from JamesFreeman/analysis-vZx3mN
JamesFreeman Oct 5, 2024
b21dc06
changes
JamesFreeman Oct 5, 2024
bdc2ca9
Merge branch 'feature/new-credential-managers' of github.com:JamesFre…
JamesFreeman Oct 5, 2024
ccabe0a
change to XeroException
JamesFreeman Oct 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions src/Exceptions/OAuthException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@

namespace Webfox\Xero\Exceptions;

use Exception;
use Throwable;

class OAuthException extends Exception
class OAuthException extends XeroException
{
public function __construct($message, $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}

public function __toString()
{
return __CLASS__.": [{$this->code}]: {$this->message}\n";
}
}
7 changes: 7 additions & 0 deletions src/Exceptions/XeroCredentialsNotFound.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Webfox\Xero\Exceptions;

class XeroCredentialsNotFound extends XeroException
{
}
19 changes: 19 additions & 0 deletions src/Exceptions/XeroException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Webfox\Xero\Exceptions;

use Exception;
use Throwable;

abstract class XeroException extends Exception
{
public function __construct($message, $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}

public function __toString()
{
return __CLASS__.": [{$this->code}]: {$this->message}\n";
}
}
7 changes: 7 additions & 0 deletions src/Exceptions/XeroTenantNotFound.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Webfox\Xero\Exceptions;

class XeroTenantNotFound extends XeroException
{
}
7 changes: 7 additions & 0 deletions src/Exceptions/XeroUserNotAuthenticated.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Webfox\Xero\Exceptions;

class XeroUserNotAuthenticated extends XeroException
{
}
93 changes: 3 additions & 90 deletions src/Oauth2CredentialManagers/ArrayStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,86 +2,19 @@

namespace Webfox\Xero\Oauth2CredentialManagers;

use Illuminate\Session\Store;
use League\OAuth2\Client\Token\AccessTokenInterface;
use Webfox\Xero\Oauth2Provider;
use Webfox\Xero\Exceptions\XeroCredentialsNotFound;
use Webfox\Xero\OauthCredentialManager;

class ArrayStore implements OauthCredentialManager
class ArrayStore extends BaseCredentialManager implements OauthCredentialManager
{
public ?array $dataStorage = null;

public function __construct(protected Store $session, protected Oauth2Provider $oauthProvider)
{
}

public function getAccessToken(): string
{
return $this->data('token');
}

public function getRefreshToken(): string
{
return $this->data('refresh_token');
}

public function getTenants(): ?array
{
return $this->data('tenants');
}

public function getTenantId(int $tenant = 0): string
{
if (! isset($this->data('tenants')[$tenant])) {
throw new \Exception('No such tenant exists');
}

return $this->data('tenants')[$tenant]['Id'];
}

public function getExpires(): int
{
return $this->data('expires');
}

public function getState(): string
{
return $this->session->get('xero_oauth2_state') ?? '';
}

public function getAuthorizationUrl(): string
{
$redirectUrl = $this->oauthProvider->getAuthorizationUrl(['scope' => config('xero.oauth.scopes')]);
$this->session->put('xero_oauth2_state', $this->oauthProvider->getState());

return $redirectUrl;
}

public function getData(): array
{
return $this->data();
}

public function exists(): bool
{
return $this->dataStorage !== null;
}

public function isExpired(): bool
{
return time() >= $this->data('expires');
}

public function refresh(): void
{
$newAccessToken = $this->oauthProvider->getAccessToken('refresh_token', [
'grant_type' => 'refresh_token',
'refresh_token' => $this->getRefreshToken(),
]);

$this->store($newAccessToken);
}

public function store(AccessTokenInterface $token, array $tenants = null): void
{
$this->dataStorage = [
Expand All @@ -93,30 +26,10 @@ public function store(AccessTokenInterface $token, array $tenants = null): void
];
}

public function getUser(): ?array
{
try {
$jwt = new \XeroAPI\XeroPHP\JWTClaims();
$jwt->setTokenId($this->data('id_token'));
$decodedToken = $jwt->decode();

return [
'given_name' => $decodedToken->getGivenName(),
'family_name' => $decodedToken->getFamilyName(),
'email' => $decodedToken->getEmail(),
'user_id' => $decodedToken->getXeroUserId(),
'username' => $decodedToken->getPreferredUsername(),
'session_id' => $decodedToken->getGlobalSessionId(),
];
} catch (\Throwable $e) {
return null;
}
}

protected function data(string $key = null)
{
if (! $this->exists()) {
throw new \Exception('Xero oauth credentials are missing');
throw new XeroCredentialsNotFound('Xero oauth credentials are missing');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than specifying the same message in multiple places, let's just make these the default values for the $message parameter across each of the exceptions.

}

return $key === null ? $this->dataStorage : $this->dataStorage[$key] ?? null;
Expand Down
20 changes: 20 additions & 0 deletions src/Oauth2CredentialManagers/AuthenticatedUserStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Webfox\Xero\Oauth2CredentialManagers;

use Illuminate\Support\Facades\Auth;
use Webfox\Xero\Exceptions\XeroUserNotAuthenticated;

class AuthenticatedUserStore extends ModelStore
{
public function __construct()
{
if (! Auth::check()) {
throw new XeroUserNotAuthenticated('User is not authenticated');
}

parent::__construct();

$this->model = Auth::user();
}
}
104 changes: 104 additions & 0 deletions src/Oauth2CredentialManagers/BaseCredentialManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace Webfox\Xero\Oauth2CredentialManagers;

use Illuminate\Session\Store;
use Webfox\Xero\Exceptions\XeroTenantNotFound;
use Webfox\Xero\Oauth2Provider;
use XeroAPI\XeroPHP\JWTClaims;

abstract class BaseCredentialManager
{
protected Store $session;
protected Oauth2Provider $oauthProvider;

public function __construct()
{
$this->session = app(Store::class);
$this->oauthProvider = app(Oauth2Provider::class);
}

abstract protected function data(string $key = null);

public function getAccessToken(): string
{
return $this->data('token');
}

public function getRefreshToken(): string
{
return $this->data('refresh_token');
}

public function getTenants(): ?array
{
return $this->data('tenants');
}

public function getTenantId(int $tenant = 0): string
{
if (! isset($this->data('tenants')[$tenant])) {
throw new XeroTenantNotFound('No such tenant exists');
}

return $this->data('tenants')[$tenant]['Id'];
}

public function getExpires(): int
{
return $this->data('expires');
}

public function getData(): array
{
return $this->data();
}

public function getUser(): ?array
{
try {
$jwt = new JWTClaims();
$jwt->setTokenId($this->data('id_token'));
$decodedToken = $jwt->decode();

return [
'given_name' => $decodedToken->getGivenName(),
'family_name' => $decodedToken->getFamilyName(),
'email' => $decodedToken->getEmail(),
'user_id' => $decodedToken->getXeroUserId(),
'username' => $decodedToken->getPreferredUsername(),
'session_id' => $decodedToken->getGlobalSessionId(),
];
} catch (\Throwable $e) {
return null;
}
}

public function isExpired(): bool
{
return time() >= $this->data('expires');
}

public function refresh(): void
{
$newAccessToken = $this->oauthProvider->getAccessToken('refresh_token', [
'grant_type' => 'refresh_token',
'refresh_token' => $this->getRefreshToken(),
]);

$this->store($newAccessToken);
}

public function getState(): string
{
return $this->session->get('xero_oauth2_state') ?? '';
}

public function getAuthorizationUrl(): string
{
$redirectUrl = $this->oauthProvider->getAuthorizationUrl(['scope' => config('xero.oauth.scopes')]);
$this->session->put('xero_oauth2_state', $this->oauthProvider->getState());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also declare oauthProvider and session as properties on the BaseCredentialManager too.


return $redirectUrl;
}
}
Loading