Skip to content

Commit

Permalink
Amazon Pay API SDK PHP 2.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
akshitaWaldia committed Jan 24, 2023
1 parent 6c579f0 commit 8b7a52e
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 172 deletions.
57 changes: 42 additions & 15 deletions Amazon/Pay/API/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@

class Client implements ClientInterface
{
const SDK_VERSION = '2.4.0';
const SDK_VERSION = '2.5.0';
const HASH_ALGORITHM = 'sha256';
const AMAZON_SIGNATURE_ALGORITHM = 'AMZN-PAY-RSASSA-PSS';
const API_VERSION = 'v2';
const SALT_LENGTH = 20;


private $config = array();

private $apiServiceUrls = array(
Expand All @@ -38,6 +36,8 @@ public function __construct($config = null) {
throw new \Exception('$config is of the incorrect type ' . gettype($config) . ' and should be of the type array');
}

//V2 Algorithm accepts only 'eu', 'na' and 'jp' as region
$config['region'] = $this->regionMappings[$config['region']];
$this->config = $config;

if (!empty($config['sandbox'])) {
Expand All @@ -64,6 +64,19 @@ public function __get($name)
}
}

/* Get signature algorithm from config, use AMZN-PAY-RSASSA-PSS by default if not specified */
private function getAlgorithm() {
if (!empty($this->config['algorithm'])) {
if ($this->config['algorithm'] === 'AMZN-PAY-RSASSA-PSS' || $this->config['algorithm'] === 'AMZN-PAY-RSASSA-PSS-V2') {
return $this->config['algorithm'];
} else {
throw new \Exception($this->config['algorithm'] . ' is not a valid algorithm');
}
} else {
return 'AMZN-PAY-RSASSA-PSS';
}
}

/* Create API service URL and the Endpoint path */
private function createServiceUrl()
{
Expand Down Expand Up @@ -345,7 +358,7 @@ public function getPostSignedHeaders($http_request_method, $request_uri, $reques
'x-amz-pay-host' => $this->getHost($request_uri),
'x-amz-pay-date' => $timeStamp,
'x-amz-pay-region' => $this->config['region'],
'authorization' => self::AMAZON_SIGNATURE_ALGORITHM . " PublicKeyId=" . $public_key_id . ", " . $signedHeaders,
'authorization' => $this->getAlgorithm() . " PublicKeyId=" . $public_key_id . ", " . $signedHeaders,
'user-agent' => $this->constructUserAgentHeader()
);

Expand Down Expand Up @@ -379,7 +392,7 @@ public function createSignature($http_request_method, $request_uri, $request_par
$hashedPayload
);

$hashedCanonicalRequest = self::AMAZON_SIGNATURE_ALGORITHM . "\n" . $this->hexAndHash($canonicalRequest);
$hashedCanonicalRequest = $this->getAlgorithm() . "\n" . $this->hexAndHash($canonicalRequest);

$signature = $rsa->sign($hashedCanonicalRequest);
if ($signature === false) {
Expand All @@ -402,8 +415,7 @@ public function generateButtonSignature($payload) {

// stripcslashes function is used on payload to unescape sequences like http:\/\/ to http://
// and \"hello\" to "hello"
$hashedButtonRequest = self::AMAZON_SIGNATURE_ALGORITHM . "\n" . $this->hexAndHash(isset($payload) ? stripcslashes($payload) : '');

$hashedButtonRequest = $this->getAlgorithm() . "\n" . $this->hexAndHash(isset($payload) ? stripcslashes($payload) : '');
$signature = $rsa->sign($hashedButtonRequest);
if ($signature === false) {
throw new \Exception('Unable to sign request, is your RSA private key valid?');
Expand All @@ -415,17 +427,16 @@ public function generateButtonSignature($payload) {

private function setupRSA() {
$key_spec = $this->config['private_key'];

$salt_length = $this->getAlgorithm() === 'AMZN-PAY-RSASSA-PSS' ? 20 : 32;
if ((strpos($key_spec, 'BEGIN RSA PRIVATE KEY') === false) && (strpos($key_spec, 'BEGIN PRIVATE KEY') === false)) {
$contents = file_get_contents($key_spec);
if ($contents === false) {
throw new \Exception('Unable to load file: ' . $key_spec);
}
$rsa = RSA::loadPrivateKey($contents)->withSaltLength(self::SALT_LENGTH);
$rsa = RSA::loadPrivateKey($contents)->withSaltLength($salt_length);
} else {
$rsa = RSA::loadPrivateKey($key_spec)->withSaltLength(self::SALT_LENGTH);
$rsa = RSA::loadPrivateKey($key_spec)->withSaltLength($salt_length);
}

return $rsa;
}

Expand All @@ -444,6 +455,18 @@ public function testPrivateKeyIntegrity() {
return true;
}

private function parseShippingAddressList( &$response ) {
$responsePayload = json_decode($response['response'], true);

if(isset($responsePayload['shippingAddressList'])) {
$responsePayload['shippingAddressList'] = array_map(function ($shippingAddress) {
return json_decode($shippingAddress, true);
}, $responsePayload['shippingAddressList']);
$response['response'] = json_encode($responsePayload, JSON_UNESCAPED_UNICODE);
}

return $response;
}

public function apiCall($method, $urlFragment, $payload, $headers = null, $queryParams = null) {
if (is_array($payload)) {
Expand Down Expand Up @@ -553,19 +576,22 @@ public function createCheckoutSession($payload, $headers)

public function getCheckoutSession($checkoutSessionId, $headers = null)
{
return $this->apiCall('GET', self::API_VERSION . '/checkoutSessions/' . $checkoutSessionId, null, $headers);
$response = $this->apiCall('GET', self::API_VERSION . '/checkoutSessions/' . $checkoutSessionId, null, $headers);
return $this->parseShippingAddressList($response);
}


public function updateCheckoutSession($checkoutSessionId, $payload, $headers = null)
{
return $this->apiCall('PATCH', self::API_VERSION . '/checkoutSessions/' . $checkoutSessionId, $payload, $headers);
$response = $this->apiCall('PATCH', self::API_VERSION . '/checkoutSessions/' . $checkoutSessionId, $payload, $headers);
return $this->parseShippingAddressList($response);
}


public function completeCheckoutSession($checkoutSessionId, $payload, $headers = null)
{
return $this->apiCall('POST', self::API_VERSION . '/checkoutSessions/' . $checkoutSessionId . '/complete', $payload, $headers);
$response = $this->apiCall('POST', self::API_VERSION . '/checkoutSessions/' . $checkoutSessionId . '/complete', $payload, $headers);
return $this->parseShippingAddressList($response);
}


Expand Down Expand Up @@ -624,3 +650,4 @@ public function getRefund($refundId, $headers = null)

}
?>

5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### Version 2.5.0 - January 2023
* Introducting new signature generation algorithm AMZN-PAY-RSASSA-PSS-V2 & increasing salt length from 20 to 32.
* Added support for handling new parameter 'shippingAddressList' in Checkout Session response. Change is fully backwards compatible.
* Note : To use new algorithm AMZN-PAY-RSASSA-PSS-V2, "algorithm" needs to be provided as an additional field in "$amazonpay_config" and also while rendering Amazon Pay button in "createCheckoutSessionConfig". The changes are backwards-compatible, SDK will use AMZN-PAY-RSASSA-PSS by default.

#### Version 2.4.0 - August 2022
* Enabled Proxy Support for HttpCurl

Expand Down
28 changes: 19 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ Namespace for this package is Amazon\Pay\API so that there are no conflicts with
'public_key_id' => 'ABC123DEF456XYZ', // RSA Public Key ID (this is not the Merchant or Seller ID)
'private_key' => 'keys/private.pem', // Path to RSA Private Key (or a string representation)
'sandbox' => true, // true (Sandbox) or false (Production) boolean
'region' => 'us' // Must be one of: 'us', 'eu', 'jp'
'region' => 'us', // Must be one of: 'us', 'eu', 'jp'
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2' //Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified
);
```
If you have created environment specific keys (i.e Public Key Starts with LIVE or SANDBOX) in Seller Central, then use those PublicKeyId & PrivateKey. In this case, there is no need to pass the Sandbox parameter to the ApiConfiguration.
Expand All @@ -73,7 +74,8 @@ If you have created environment specific keys (i.e Public Key Starts with LIVE o
$amazonpay_config = array(
'public_key_id' => 'MY_PUBLIC_KEY_ID', // LIVE-XXXXX or SANDBOX-XXXXX
'private_key' => 'keys/private.pem', // Path to RSA Private Key (or a string representation)
'region' => 'us' // Must be one of: 'us', 'eu', 'jp'
'region' => 'us', // Must be one of: 'us', 'eu', 'jp'
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2' //Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified
);
```

Expand All @@ -84,6 +86,7 @@ If you have want to enable proxy support, you can set it in the $amazonpay_confi
'private_key' => 'keys/private.pem', // Path to RSA Private Key (or a string representation)
'sandbox' => true, // true (Sandbox) or false (Production) boolean
'region' => 'us', // Must be one of: 'us', 'eu', 'jp'
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2', //Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified
'proxy' => [
'host' => 'proxy_host',
'port' => 'proxy_port',
Expand Down Expand Up @@ -242,7 +245,8 @@ An alternate way to do Step 2 would be to use PHP arrays and programmatically ge
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => false
'sandbox' => false,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);
$payload = array(
'amazonOrderReferenceId' => 'P01-0000000-0000000',
Expand Down Expand Up @@ -280,7 +284,8 @@ An alternate way to do Step 2 would be to use PHP arrays and programmatically ge
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => true
'sandbox' => true,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);
$payload = array(
'webCheckoutDetails' => array(
Expand Down Expand Up @@ -319,7 +324,8 @@ An alternate way to do Step 2 would be to use PHP arrays and programmatically ge
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => true
'sandbox' => true,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);
$payload = array(
'webCheckoutDetails' => array(
Expand Down Expand Up @@ -358,7 +364,8 @@ An alternate way to do Step 2 would be to use PHP arrays and programmatically ge
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => true
'sandbox' => true,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);

try {
Expand Down Expand Up @@ -408,7 +415,8 @@ An alternate way to do Step 2 would be to use PHP arrays and programmatically ge
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => true
'sandbox' => true,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);

$payload = array(
Expand Down Expand Up @@ -456,7 +464,8 @@ An alternate way to do Step 2 would be to use PHP arrays and programmatically ge
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => true
'sandbox' => true,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);

$payload = array(
Expand Down Expand Up @@ -502,7 +511,8 @@ The signatures generated by this helper function are only valid for the Checkout
'public_key_id' => 'MY_PUBLIC_KEY_ID',
'private_key' => 'keys/private.pem',
'region' => 'US',
'sandbox' => true
'sandbox' => true,
'algorithm' => 'AMZN-PAY-RSASSA-PSS-V2',
);

$client = new Amazon\Pay\API\Client($amazonpay_config);
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "amzn/amazon-pay-api-sdk-php",
"type": "library",
"description": "Amazon Pay API SDK (PHP)",
"version": "2.4.0",
"version": "2.5.0",
"keywords": [
"amazon",
"pay",
Expand Down

0 comments on commit 8b7a52e

Please sign in to comment.