mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
Create an encryption service
This commit is contained in:
parent
54f85b5ed6
commit
bb92fc1370
6 changed files with 195 additions and 0 deletions
|
|
@ -59,6 +59,7 @@
|
|||
"lexik/jwt-authentication-bundle": "^3.1",
|
||||
"liip/imagine-bundle": "^2.13",
|
||||
"pagerfanta/pagerfanta": "^4.0",
|
||||
"paragonie/halite": "^5.0",
|
||||
"payum/offline": "^1.7.5",
|
||||
"payum/payum-bundle": "^2.6",
|
||||
"php-http/discovery": "^1.20",
|
||||
|
|
|
|||
71
src/Sylius/Component/Payment/Encryption/Encrypter.php
Normal file
71
src/Sylius/Component/Payment/Encryption/Encrypter.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Component\Payment\Encryption;
|
||||
|
||||
use ParagonIE\Halite\Alerts\HaliteAlert;
|
||||
use ParagonIE\Halite\KeyFactory;
|
||||
use ParagonIE\Halite\Symmetric\Crypto;
|
||||
use ParagonIE\Halite\Symmetric\EncryptionKey;
|
||||
use ParagonIE\HiddenString\HiddenString;
|
||||
use Sylius\Component\Payment\Encryption\Exception\EncryptionException;
|
||||
|
||||
final class Encrypter implements EncrypterInterface
|
||||
{
|
||||
private const ENCRYPTION_SUFFIX = '#ENCRYPTED';
|
||||
|
||||
private const ENCRYPTION_SUFFIX_LENGTH = 10;
|
||||
|
||||
private ?EncryptionKey $key = null;
|
||||
|
||||
public function __construct(
|
||||
#[\SensitiveParameter]
|
||||
private readonly string $keyPhrase,
|
||||
#[\SensitiveParameter]
|
||||
private readonly string $keySalt,
|
||||
) {
|
||||
}
|
||||
|
||||
public function encrypt(string $data): string
|
||||
{
|
||||
try {
|
||||
return Crypto::encrypt(new HiddenString($data), $this->getKey()) . self::ENCRYPTION_SUFFIX;
|
||||
} catch (\TypeError|\SodiumException|HaliteAlert $exception) {
|
||||
throw EncryptionException::cannotEncrypt($exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function decrypt(string $data): string
|
||||
{
|
||||
if (!str_ends_with($data, self::ENCRYPTION_SUFFIX)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = substr($data, 0, -self::ENCRYPTION_SUFFIX_LENGTH);
|
||||
|
||||
return Crypto::decrypt($data, $this->getKey())->getString();
|
||||
} catch (\TypeError|\SodiumException|HaliteAlert $exception) {
|
||||
throw EncryptionException::cannotDecrypt($exception);
|
||||
}
|
||||
}
|
||||
|
||||
private function getKey(): EncryptionKey
|
||||
{
|
||||
if (null === $this->key) {
|
||||
$this->key = KeyFactory::deriveEncryptionKey(new HiddenString($this->keyPhrase), $this->keySalt);
|
||||
}
|
||||
|
||||
return $this->key;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Component\Payment\Encryption;
|
||||
|
||||
use Sylius\Component\Payment\Encryption\Exception\EncryptionException;
|
||||
|
||||
interface EncrypterInterface
|
||||
{
|
||||
/** @throws EncryptionException */
|
||||
public function encrypt(string $data): string;
|
||||
|
||||
/** @throws EncryptionException */
|
||||
public function decrypt(string $data): string;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Component\Payment\Encryption\Exception;
|
||||
|
||||
final class EncryptionException extends \RuntimeException
|
||||
{
|
||||
public static function cannotEncrypt(\Throwable $previousException): self
|
||||
{
|
||||
return new self(
|
||||
message: 'Cannot encrypt data.',
|
||||
previous: $previousException,
|
||||
);
|
||||
}
|
||||
|
||||
public static function cannotDecrypt(\Throwable $previousException): self
|
||||
{
|
||||
return new self(
|
||||
message: 'Cannot decrypt data.',
|
||||
previous: $previousException,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
],
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"paragonie/halite": "^5.0",
|
||||
"sylius/registry": "^1.6",
|
||||
"sylius/resource": "^1.12",
|
||||
"symfony/uid": "^6.4 || ^7.1"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace spec\Sylius\Component\Payment\Encryption;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Component\Payment\Encryption\EncrypterInterface;
|
||||
use Sylius\Component\Payment\Encryption\Exception\EncryptionException;
|
||||
|
||||
final class EncrypterSpec extends ObjectBehavior
|
||||
{
|
||||
function let(): void
|
||||
{
|
||||
$this->beConstructedWith('a_very_strong_password', 'very_strong_salt');
|
||||
}
|
||||
|
||||
function it_is_an_encrypter(): void
|
||||
{
|
||||
$this->shouldImplement(EncrypterInterface::class);
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_it_cannot_encrypt(): void
|
||||
{
|
||||
$this->beConstructedWith('', '');
|
||||
$this->shouldThrow(EncryptionException::class)->during('encrypt', ['data']);
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_it_cannot_decrypt(): void
|
||||
{
|
||||
$this->beConstructedWith('', '');
|
||||
$this->shouldThrow(EncryptionException::class)->during('decrypt', ['data#ENCRYPTED']);
|
||||
}
|
||||
|
||||
function it_encrypts_data(): void
|
||||
{
|
||||
$this->encrypt('data')->shouldBeString();
|
||||
$this->encrypt('data')->shouldNotBe('data');
|
||||
$this->encrypt('data')->shouldEndWith('#ENCRYPTED');
|
||||
}
|
||||
|
||||
function it_decrypts_data(): void
|
||||
{
|
||||
$data = 'data';
|
||||
$encryptedData = $this->getWrappedObject()->encrypt($data);
|
||||
|
||||
$this->decrypt($encryptedData)->shouldNotEndWith('#ENCRYPTED');
|
||||
$this->decrypt($encryptedData)->shouldBe($data);
|
||||
}
|
||||
|
||||
function it_does_nothing_when_data_is_not_marked_as_encrypted(): void
|
||||
{
|
||||
$this->decrypt('data')->shouldBe('data');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue