Skip to content

Commit

Permalink
Improve proxy DX (#76)
Browse files Browse the repository at this point in the history
* reduce proxy complexity

* Pass headers into proxy rather than an auth token

* Test headers are sent
  • Loading branch information
keithbrink authored Nov 8, 2024
1 parent 4ab972a commit ef74368
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 132 deletions.
26 changes: 4 additions & 22 deletions src/AmznSPAConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class AmznSPAConfig
private GrantlessToken $grantless_token;
private RestrictedDataToken $restricted_data_token;
private LoggerInterface $logger;
private ?Proxy $proxy;

public function __construct(
string $marketplace_id,
Expand All @@ -49,7 +50,7 @@ public function __construct(
?CarbonImmutable $grantless_access_token_expires_at = null,
?string $restricted_data_token = null,
?CarbonImmutable $restricted_data_token_expires_at = null,
private ?Proxy $proxy = null
?Proxy $proxy = null
) {
$this->validateStringEnum($marketplace_id, MarketplacesList::allIdentifiers());

Expand Down Expand Up @@ -78,6 +79,7 @@ public function __construct(
);

$this->logger = $logger ?: new Logger();
$this->proxy = $proxy;
}

public function getHttp(): PendingRequest
Expand Down Expand Up @@ -140,31 +142,11 @@ public function shouldUseTestEndpoints(): bool
return $this->use_test_endpoints;
}

public function shouldUseProxy(): bool
{
return $this->proxy?->url && $this->proxy?->auth_token;
}

public function getProxy(): Proxy|null
{
return $this->proxy;
}

public function setProxy(Proxy $proxy): void
{
$this->proxy = $proxy;
}

public function getProxyUrl(): string|null
{
return $this->proxy?->url;
}

public function getProxyAuthToken(): string|null
{
return $this->proxy?->auth_token;
}

public function shouldGetRdtTokens(): bool
{
return $this->get_rdt_tokens;
Expand Down Expand Up @@ -230,6 +212,6 @@ public function setMarketplace(string $marketplace_id): void

public function isPropertySet(string $property): bool
{
return isset($this->$property) && !is_null($this->$property);
return isset($this->$property) && ! is_null($this->$property);
}
}
16 changes: 7 additions & 9 deletions src/AmznSPAHttp.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,8 @@ private function refreshRdtToken(string $url, string $method)

private function setupHttp(PendingRequest $http, bool $grantless = false, string $url = '', string $method = ''): void
{
if ($this->config->shouldUseProxy()) {
$this->http = $http->withHeaders([
'Authorization' => "Bearer {$this->config->getProxyAuthToken()}"
]);
if ($proxy = $this->config->getProxy()) {
$this->http = $http->withHeaders($proxy->headers);
} else {
$this->http = $http->withHeaders([
'x-amz-access-token' => $this->getToken($grantless, $url, $method),
Expand Down Expand Up @@ -476,11 +474,11 @@ private function isAuthenticationException(RequestException $e): bool

$message = Arr::get($e->response->json(), 'errors.0.message', '');
if (Str::contains($message, [
'Access to requested resource is denied',
'Invalid partyId',
'hasn\'t registered in FBA in marketplace',
'No MWS Authorization exists',
'No MWS Authorization found',
'Access to requested resource is denied',
'Invalid partyId',
'hasn\'t registered in FBA in marketplace',
'No MWS Authorization exists',
'No MWS Authorization found',
])) {
return true;
}
Expand Down
8 changes: 3 additions & 5 deletions src/Data/Proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

namespace Jasara\AmznSPA\Data;

use Jasara\AmznSPA\Data\Base\Data;

class Proxy extends Data
class Proxy
{
public function __construct(
public ?string $url,
public ?string $auth_token,
public readonly string $url,
public readonly array $headers,
) {
}
}
6 changes: 3 additions & 3 deletions src/Resources/ResourceGetter.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public function getListingsItems(): ListingsItemsResource

private function constructResource(string $class, ?string $grantless_resource = null): ResourceContract
{
$url = $this->config->shouldUseProxy() ? $this->config->getProxyUrl() : $this->config->getMarketplace()->getBaseUrl();
$url = $this->config->getProxy() ? $this->config->getProxy()->url : $this->config->getMarketplace()->getBaseUrl();

return new $class(
$this->validateAndSetupHttpForStandardResource($grantless_resource),
Expand All @@ -158,10 +158,10 @@ private function constructResource(string $class, ?string $grantless_resource =

private function validateAndSetupHttpForStandardResource(?string $grantless_resource = null): AmznSPAHttp
{
if (!$this->config->shouldUseProxy()) {
if (! $this->config->getProxy()) {
$this->validateObjectProperties($this->config->getApplicationKeys(), ['lwa_client_id', 'lwa_client_secret', 'aws_access_key', 'aws_secret_key']);

if (!$grantless_resource) {
if (! $grantless_resource) {
$this->validateObjectProperties($this->config->getTokens(), ['refresh_token']);
}
}
Expand Down
27 changes: 27 additions & 0 deletions tests/Setup/SetupAmznSPAConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Support\Str;
use Jasara\AmznSPA\AmznSPAConfig;
use Jasara\AmznSPA\Constants\MarketplacesList;
use Jasara\AmznSPA\Data\Proxy;

trait SetupAmznSPAConfig
{
Expand All @@ -31,6 +32,32 @@ public function setupMinimalConfig(string $marketplace_id = null, Factory $http
return $config;
}

public function setupMinimalProxyConfig(
Proxy $proxy,
string $marketplace_id = null,
Factory $http = null,
): AmznSPAConfig {
$config = new AmznSPAConfig(
marketplace_id: $marketplace_id ?: MarketplacesList::allIdentifiers()[rand(0, 15)],
application_id: Str::random(),
redirect_url: Str::random() . '.com',
lwa_refresh_token: Str::random(),
lwa_access_token: Str::random(),
grantless_access_token: Str::random(),
aws_access_key: Str::random(),
aws_secret_key: Str::random(),
lwa_client_id: Str::random(),
lwa_client_secret: Str::random(),
proxy: $proxy,
);

if ($http) {
$config->setHttp($http);
}

return $config;
}

public function setupLiveConfig(): AmznSPAConfig
{
$config = new AmznSPAConfig(
Expand Down
86 changes: 0 additions & 86 deletions tests/Unit/AmznSPAConfigProxyTest.php

This file was deleted.

13 changes: 13 additions & 0 deletions tests/Unit/AmznSPAConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Jasara\AmznSPA\Data\ApplicationKeys;
use Jasara\AmznSPA\Data\AuthTokens;
use Jasara\AmznSPA\Data\GrantlessToken;
use Jasara\AmznSPA\Data\Proxy;
use Jasara\AmznSPA\Data\RestrictedDataToken;
use Jasara\AmznSPA\Exceptions\AuthenticationException;
use PHPUnit\Framework\Attributes\CoversClass;
Expand Down Expand Up @@ -45,6 +46,14 @@ public function testGetNewConfig()
$restricted_data_token = Str::random();
$restricted_data_token_expires_at = CarbonImmutable::now()->addSeconds(rand(100, 500));

$proxy_auth_token = Str::random();
$proxy = new Proxy(
url: Str::random(),
headers: [
'Authorization' => "Bearer {$proxy_auth_token}",
],
);

$config = new AmznSPAConfig(
marketplace_id: $marketplace_id,
application_id: $application_id,
Expand All @@ -61,6 +70,7 @@ public function testGetNewConfig()
restricted_data_token: $restricted_data_token,
restricted_data_token_expires_at: $restricted_data_token_expires_at,
use_test_endpoints: true,
proxy: $proxy,
);

$this->assertInstanceOf(Marketplace::class, $config->getMarketplace());
Expand Down Expand Up @@ -91,6 +101,9 @@ public function testGetNewConfig()

$this->assertTrue($config->shouldUseTestEndpoints());
$this->assertTrue($config->shouldGetRdtTokens());

$this->assertEquals($proxy->url, $config->getProxy()->url);
$this->assertEquals($proxy->headers, $config->getProxy()->headers);
}

public function testSetters()
Expand Down
41 changes: 38 additions & 3 deletions tests/Unit/AmznSPAHttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,41 @@ function (Request $request) {
$http->assertSentInOrder($request_validation);
}

public function testSetProxyHeaders()
{
$http = $this->fakeHttpStub(['orders/get-orders']);

$proxy_auth_token = Str::random();
$proxy = new Proxy(
url: 'https://www.example.com',
headers: [
'Authorization' => "Bearer {$proxy_auth_token}",
'X-Marketplace-Id' => 'ATVPDKIKX0DER',
],
);

$config = $this->setupMinimalProxyConfig($proxy, null, $http);

$amzn = new AmznSPA($config);
$amzn = $amzn->usingMarketplace('ATVPDKIKX0DER');
$amzn->orders->getOrders(
marketplace_ids: ['ATVPDKIKX0DER'],
);

$request_validation = [
function (Request $request) use ($proxy_auth_token) {
$this->assertEquals('GET', $request->method());
$this->assertEquals('https://www.example.com/orders/v0/orders?MarketplaceIds=ATVPDKIKX0DER', urldecode($request->url()));
$this->assertEquals("Bearer {$proxy_auth_token}", $request->header('Authorization')[0]);
$this->assertEquals('ATVPDKIKX0DER', $request->header('X-Marketplace-Id')[0]);

return true;
},
];

$http->assertSentInOrder($request_validation);
}

public function testInvalidPartyId()
{
$this->expectException(AuthenticationException::class);
Expand Down Expand Up @@ -482,13 +517,13 @@ public function testSetupHttpProxy()
$config = new AmznSPAConfig(
marketplace_id: MarketplacesList::allIdentifiers()[rand(0, 15)],
application_id: Str::random(),
proxy: Proxy::from(
proxy: new Proxy(
url: 'https://www.amazon.com',
auth_token: Str::random(),
headers: [],
)
);

$this->assertTrue($config->shouldUseProxy());
$this->assertNotNull($config->getProxy());

$amzn = new AmznSPA($config);

Expand Down
9 changes: 5 additions & 4 deletions tests/Unit/Data/ProxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ class ProxyTest extends UnitTestCase
{
public function testSetupTokens()
{
$proxy_url = Str::random();
$proxy_auth_token = Str::random();
$proxy = new Proxy(
url: $proxy_url,
auth_token: $proxy_auth_token
url: $proxy_url = Str::random(),
headers: [
'Authorization' => "Bearer {$proxy_auth_token}",
],
);

$this->assertEquals($proxy_url, $proxy->url);
$this->assertEquals($proxy_auth_token, $proxy->auth_token);
$this->assertEquals("Bearer {$proxy_auth_token}", $proxy->headers['Authorization']);
}
}

0 comments on commit ef74368

Please sign in to comment.