diff --git a/lib/PayPal/Auth/OAuthTokenCredential.php b/lib/PayPal/Auth/OAuthTokenCredential.php index f38cd6f..d84dfe0 100644 --- a/lib/PayPal/Auth/OAuthTokenCredential.php +++ b/lib/PayPal/Auth/OAuthTokenCredential.php @@ -11,6 +11,7 @@ use PayPal\Exception\PayPalConfigurationException; use PayPal\Exception\PayPalConnectionException; use PayPal\Handler\IPayPalHandler; use PayPal\Rest\ApiContext; +use PayPal\Security\Cipher; /** * Class OAuthTokenCredential @@ -74,6 +75,13 @@ class OAuthTokenCredential extends PayPalResourceModel */ private $tokenCreateTime; + /** + * Instance of cipher used to encrypt/decrypt data while storing in cache. + * + * @var Cipher + */ + private $cipher; + /** * Construct * @@ -84,6 +92,7 @@ class OAuthTokenCredential extends PayPalResourceModel { $this->clientId = $clientId; $this->clientSecret = $clientSecret; + $this->cipher = new Cipher($this->clientSecret); $this->logger = PayPalLoggingManager::getInstance(__CLASS__); } @@ -120,9 +129,20 @@ class OAuthTokenCredential extends PayPalResourceModel $token = AuthorizationCache::pull($config, $this->clientId); if ($token) { // We found it - $this->accessToken = $token['accessToken']; + // This code block is for backward compatibility only. + if (array_key_exists('accessToken', $token)) { + $this->accessToken = $token['accessToken']; + } + $this->tokenCreateTime = $token['tokenCreateTime']; $this->tokenExpiresIn = $token['tokenExpiresIn']; + + // Case where we have an old unencrypted cache file + if (!array_key_exists('accessTokenEncrypted', $token)) { + AuthorizationCache::push($config, $this->clientId, $this->encrypt($this->accessToken), $this->tokenCreateTime, $this->tokenExpiresIn); + } else { + $this->accessToken = $this->decrypt($token['accessTokenEncrypted']); + } } // Check if Access Token is not null and has not expired. @@ -137,11 +157,12 @@ class OAuthTokenCredential extends PayPalResourceModel $this->accessToken = null; } + // If accessToken is Null, obtain a new token if ($this->accessToken == null) { // Get a new one by making calls to API $this->updateAccessToken($config); - AuthorizationCache::push($config, $this->clientId, $this->accessToken, $this->tokenCreateTime, $this->tokenExpiresIn); + AuthorizationCache::push($config, $this->clientId, $this->encrypt($this->accessToken), $this->tokenCreateTime, $this->tokenExpiresIn); } return $this->accessToken; @@ -231,6 +252,7 @@ class OAuthTokenCredential extends PayPalResourceModel * * @param array $config * @return null + * @throws PayPalConnectionException */ private function generateAccessToken($config, $refreshToken = null) { @@ -259,4 +281,26 @@ class OAuthTokenCredential extends PayPalResourceModel return $this->accessToken; } + + /** + * Helper method to encrypt data using clientSecret as key + * + * @param $data + * @return string + */ + public function encrypt($data) + { + return $this->cipher->encrypt($data); + } + + /** + * Helper method to decrypt data using clientSecret as key + * + * @param $data + * @return string + */ + public function decrypt($data) + { + return $this->cipher->decrypt($data); + } } diff --git a/lib/PayPal/Cache/AuthorizationCache.php b/lib/PayPal/Cache/AuthorizationCache.php index 32649a2..b37b4eb 100644 --- a/lib/PayPal/Cache/AuthorizationCache.php +++ b/lib/PayPal/Cache/AuthorizationCache.php @@ -49,6 +49,7 @@ abstract class AuthorizationCache * @param $accessToken * @param $tokenCreateTime * @param $tokenExpiresIn + * @throws \Exception */ public static function push($config = null, $clientId, $accessToken, $tokenCreateTime, $tokenExpiresIn) { @@ -58,7 +59,7 @@ abstract class AuthorizationCache $cachePath = self::cachePath($config); if (!is_dir(dirname($cachePath))) { if (mkdir(dirname($cachePath), 0755, true) == false) { - return; + throw new \Exception("Failed to create directory at $cachePath"); } } @@ -68,12 +69,14 @@ abstract class AuthorizationCache if (is_array($tokens)) { $tokens[$clientId] = array( 'clientId' => $clientId, - 'accessToken' => $accessToken, + 'accessTokenEncrypted' => $accessToken, 'tokenCreateTime' => $tokenCreateTime, 'tokenExpiresIn' => $tokenExpiresIn ); } - file_put_contents($cachePath, json_encode($tokens)); + if(!file_put_contents($cachePath, json_encode($tokens))) { + throw new \Exception("Failed to write cache"); + }; } /** diff --git a/lib/PayPal/Security/Cipher.php b/lib/PayPal/Security/Cipher.php new file mode 100644 index 0000000..3168ff0 --- /dev/null +++ b/lib/PayPal/Security/Cipher.php @@ -0,0 +1,57 @@ +$secretKey = $secretKey; + } + + /** + * Encrypts the input text using the cipher key + * + * @param $input + * @return string + */ + function encrypt($input) + { + // Create a random IV. Not using mcrypt to generate one, as to not have a dependency on it. + $iv = substr(uniqid("", true), 0, Cipher::IV_SIZE); + // Encrypt the data + $encrypted = openssl_encrypt($input, "AES-256-CBC", $this->secretKey, 0, $iv); + // Encode the data with IV as prefix + return base64_encode($iv . $encrypted); + } + + /** + * Decrypts the input text from the cipher key + * + * @param $input + * @return string + */ + function decrypt($input) + { + // Decode the IV + data + $input = base64_decode($input); + // Remove the IV + $iv = substr($input, 0, Cipher::IV_SIZE); + // Return Decrypted Data + return openssl_decrypt(substr($input, Cipher::IV_SIZE), "AES-256-CBC", $this->secretKey, 0, $iv); + } +} diff --git a/sample/invoice/CreateInvoice.php b/sample/invoice/CreateInvoice.php index 8b50721..1f38547 100644 --- a/sample/invoice/CreateInvoice.php +++ b/sample/invoice/CreateInvoice.php @@ -23,7 +23,6 @@ $invoice = new Invoice(); $invoice ->setMerchantInfo(new MerchantInfo()) ->setBillingInfo(array(new BillingInfo())) - ->setItems(array(new InvoiceItem())) ->setNote("Medical Invoice 16 Jul, 2013 PST") ->setPaymentTerm(new PaymentTerm()) ->setShippingInfo(new ShippingInfo()); @@ -61,7 +60,8 @@ $billing[0] // ### Items List // You could provide the list of all items for // detailed breakdown of invoice -$items = $invoice->getItems(); +$items = array(); +$items[0] = new InvoiceItem(); $items[0] ->setName("Sutures") ->setQuantity(100) @@ -70,6 +70,17 @@ $items[0] $items[0]->getUnitPrice() ->setCurrency("USD") ->setValue(5); +// Second Item +$items[1] = new InvoiceItem(); +$items[1] + ->setName("Injection") + ->setQuantity(5) + ->setUnitPrice(new Currency()); + +$items[1]->getUnitPrice() + ->setCurrency("USD") + ->setValue(5); +$invoice->setItems($items); $invoice->getPaymentTerm() ->setTermType("NET_45"); diff --git a/tests/PayPal/Test/Auth/OAuthTokenCredentialTest.php b/tests/PayPal/Test/Auth/OAuthTokenCredentialTest.php index 8a6ea68..7874711 100644 --- a/tests/PayPal/Test/Auth/OAuthTokenCredentialTest.php +++ b/tests/PayPal/Test/Auth/OAuthTokenCredentialTest.php @@ -48,9 +48,11 @@ class OAuthTokenCredentialTest extends \PHPUnit_Framework_TestCase 'cache.enabled' => true, 'cache.FileName' => AuthorizationCacheTest::CACHE_FILE ); + $cred = new OAuthTokenCredential('clientId', 'clientSecret'); + //{"clientId":{"clientId":"clientId","accessToken":"accessToken","tokenCreateTime":1421204091,"tokenExpiresIn":288000000}} - AuthorizationCache::push($config, 'clientId', 'accessToken', 1421204091, 288000000); - $cred = new OAuthTokenCredential('clientId', 'clientSecret'); + AuthorizationCache::push($config, 'clientId', $cred->encrypt('accessToken'), 1421204091, 288000000); + $apiContext = new ApiContext($cred); $apiContext->setConfig($config); $this->assertEquals('clientId', $cred->getClientId()); diff --git a/tests/PayPal/Test/Cache/AuthorizationCacheTest.php b/tests/PayPal/Test/Cache/AuthorizationCacheTest.php index 8df913b..82a5e14 100644 --- a/tests/PayPal/Test/Cache/AuthorizationCacheTest.php +++ b/tests/PayPal/Test/Cache/AuthorizationCacheTest.php @@ -76,7 +76,7 @@ class AuthorizationCacheTest extends \PHPUnit_Framework_TestCase $tokens = json_decode($contents, true); $this->assertNotNull($contents); $this->assertEquals('clientId', $tokens['clientId']['clientId']); - $this->assertEquals('accessToken', $tokens['clientId']['accessToken']); + $this->assertEquals('accessToken', $tokens['clientId']['accessTokenEncrypted']); $this->assertEquals('tokenCreateTime', $tokens['clientId']['tokenCreateTime']); $this->assertEquals('tokenExpiresIn', $tokens['clientId']['tokenExpiresIn']); @@ -97,7 +97,7 @@ class AuthorizationCacheTest extends \PHPUnit_Framework_TestCase $this->assertNotNull($result); $this->assertTrue(is_array($result)); $this->assertEquals('clientId', $result['clientId']); - $this->assertEquals('accessToken', $result['accessToken']); + $this->assertEquals('accessToken', $result['accessTokenEncrypted']); $this->assertEquals('tokenCreateTime', $result['tokenCreateTime']); $this->assertEquals('tokenExpiresIn', $result['tokenExpiresIn']);