├── .github
└── workflows
│ └── tests.yaml
├── .gitignore
├── .php-cs-fixer.php
├── Annotations
├── AnnotationResolver.php
├── ParamDecryptor.php
└── ParamEncryptor.php
├── DependencyInjection
├── Compiler
│ └── LoadAnnotationService.php
├── Configuration.php
└── NzoEncryptorExtension.php
├── Encryptor
└── Encryptor.php
├── LICENSE
├── NzoUrlEncryptorBundle.php
├── README.md
├── Resources
└── config
│ └── services.yaml
├── Tests
├── Annotation
│ ├── AnnotationResolverTest.php
│ └── Fixtures
│ │ └── DummyController.php
└── Encryptor
│ └── NzoEncryptorExtensionTest.php
├── Twig
└── EncryptorExtension.php
├── composer.json
├── phpstan.neon
├── phpunit.xml.dist
└── rector.php
/.github/workflows/tests.yaml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on:
4 | pull_request: ~
5 | push:
6 | branches:
7 | - master
8 |
9 | jobs:
10 | run:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | fail-fast: false
14 | matrix:
15 | php-version:
16 | - "7.1.3"
17 | - "7.2"
18 | - "7.4"
19 | - "8.0"
20 | - "8.0"
21 | - "8.1"
22 | - "8.2"
23 | - "8.3"
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v3
27 |
28 | - name: Setup PHP
29 | uses: shivammathur/setup-php@v2
30 | with:
31 | php-version: ${{ matrix.php-version }}
32 |
33 | - name: Install dependencies
34 | run: composer install
35 |
36 | - name: Run PHPUnit tests
37 | run: |
38 | ./vendor/bin/phpunit
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /phpunit.xml
2 | /.phpunit.result.cache
3 | /composer.lock
4 | /vendor
5 | /.idea
6 | /docker-compose.yml
7 | /Makefile
8 |
--------------------------------------------------------------------------------
/.php-cs-fixer.php:
--------------------------------------------------------------------------------
1 | in(__DIR__)
5 | ->exclude([
6 | '.github/',
7 | 'vendor/',
8 | ])
9 | ;
10 |
11 | $config = (new PhpCsFixer\Config())
12 | ->setRiskyAllowed(true)
13 | ->setRules([
14 | '@PSR12' => true,
15 | '@Symfony' => true,
16 | 'array_syntax' => ['syntax' => 'short'],
17 | 'combine_consecutive_unsets' => true,
18 | 'heredoc_to_nowdoc' => true,
19 | 'no_extra_blank_lines' => ['tokens' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block']],
20 | 'no_unreachable_default_argument_value' => true,
21 | 'no_useless_else' => true,
22 | 'no_useless_return' => true,
23 | 'ordered_class_elements' => true,
24 | 'ordered_imports' => true,
25 | 'php_unit_strict' => true,
26 | 'phpdoc_order' => true,
27 | 'strict_comparison' => true,
28 | 'strict_param' => true,
29 | 'concat_space' => ['spacing' => 'one'],
30 | ])
31 | ->setFinder($finder);
32 |
33 | return $config;
34 |
--------------------------------------------------------------------------------
/Annotations/AnnotationResolver.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\Annotations;
13 |
14 | use Doctrine\Common\Annotations\AnnotationReader;
15 | use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
16 | use Symfony\Component\HttpKernel\Event\ControllerEvent;
17 |
18 | class AnnotationResolver
19 | {
20 | private $encryptor;
21 | private $reader;
22 |
23 | public function __construct(Encryptor $encryptor, ?AnnotationReader $reader = null)
24 | {
25 | $this->encryptor = $encryptor;
26 | $this->reader = $reader;
27 | }
28 |
29 | public function onKernelController(ControllerEvent $event)
30 | {
31 | if (is_array($controller = $event->getController())) {
32 | $objectController = new \ReflectionObject($controller[0]);
33 | $method = $objectController->getMethod($controller[1]);
34 | } elseif (is_object($controller) && method_exists($controller, '__invoke')) {
35 | $objectController = new \ReflectionObject($controller);
36 | $method = $objectController->getMethod('__invoke');
37 | } else {
38 | return;
39 | }
40 |
41 | // Handle PHP8 Attributes
42 | if (class_exists('ReflectionAttribute')) {
43 | if ($this->hasAnnotation($method) && !$this->reader instanceof AnnotationReader) {
44 | throw new \InvalidArgumentException('NzoEncryptor: Annotation service not loaded, PHP Attributes should be used instead.');
45 | }
46 | $annotations = $this->getAnnotation($method);
47 | } elseif ($this->reader instanceof AnnotationReader) { // Handle Annotation only without Attributes
48 | $annotations = $this->reader->getMethodAnnotations($method);
49 | } else {
50 | throw new \InvalidArgumentException('NzoEncryptor: Doctrine Annotation package must be installed, doctrine/annotations.');
51 | }
52 |
53 | foreach ($annotations as $configuration) {
54 | // handle php8 attribute
55 | if (class_exists('ReflectionAttribute')) {
56 | $configuration = $this->handleReflectionAttribute($configuration);
57 | }
58 |
59 | if ($configuration instanceof ParamEncryptor) {
60 | if (null !== $configuration->getParams()) {
61 | $request = $event->getRequest();
62 | foreach ($configuration->getParams() as $param) {
63 | if ($request->attributes->has($param)) {
64 | $decrypted = $this->encryptor->encrypt($request->attributes->get($param));
65 | $request->attributes->set($param, $decrypted);
66 | } elseif ($request->request->has($param)) {
67 | $decrypted = $this->encryptor->encrypt($request->request->get($param));
68 | $request->request->set($param, $decrypted);
69 | }
70 | }
71 | }
72 | } elseif ($configuration instanceof ParamDecryptor) {
73 | if (null !== $configuration->getParams()) {
74 | $request = $event->getRequest();
75 | foreach ($configuration->getParams() as $param) {
76 | if ($request->attributes->has($param)) {
77 | $decrypted = $this->encryptor->decrypt($request->attributes->get($param));
78 | $request->attributes->set($param, $decrypted);
79 | } elseif ($request->request->has($param)) {
80 | $decrypted = $this->encryptor->decrypt($request->request->get($param));
81 | $request->request->set($param, $decrypted);
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
88 |
89 | private function handleReflectionAttribute($configuration)
90 | {
91 | if ($configuration instanceof \ReflectionAttribute
92 | && \in_array($configuration->getName(), [ParamEncryptor::class, ParamDecryptor::class], true)) {
93 | $class = $configuration->getName();
94 | $arguments = $configuration->getArguments();
95 | $params = \is_array($arguments) && [] !== $arguments && \is_array($arguments[0]) ? $arguments[0] : [];
96 |
97 | return new $class($params);
98 | }
99 |
100 | return $configuration;
101 | }
102 |
103 | /**
104 | * @return array|mixed
105 | */
106 | private function getAnnotation($method)
107 | {
108 | return $this->reader instanceof AnnotationReader && !empty($this->reader->getMethodAnnotations($method))
109 | ? $this->reader->getMethodAnnotations($method)
110 | : $method->getAttributes();
111 | }
112 |
113 | /**
114 | * @param \ReflectionMethod $method
115 | *
116 | * @return bool
117 | */
118 | private function hasAnnotation($method)
119 | {
120 | $docComment = $method->getDocComment();
121 |
122 | return false !== $docComment && (false !== strpos($docComment, '@ParamEncryptor') || false !== strpos($docComment, '@ParamDecryptor'));
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Annotations/ParamDecryptor.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\Annotations;
13 |
14 | /**
15 | * @Annotation
16 | */
17 | #[\Attribute]
18 | class ParamDecryptor
19 | {
20 | /** @var array */
21 | private $params;
22 |
23 | public function __construct(array $params = [])
24 | {
25 | $this->params = $params;
26 | }
27 |
28 | public function getParams(): array
29 | {
30 | if (isset($this->params['value']) && \is_array($this->params['value'])) {
31 | return $this->params['value'];
32 | }
33 |
34 | return $this->params;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Annotations/ParamEncryptor.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\Annotations;
13 |
14 | /**
15 | * @Annotation
16 | */
17 | #[\Attribute]
18 | class ParamEncryptor
19 | {
20 | /** @var array */
21 | private $params;
22 |
23 | public function __construct(array $params = [])
24 | {
25 | $this->params = $params;
26 | }
27 |
28 | public function getParams(): array
29 | {
30 | if (isset($this->params['value']) && \is_array($this->params['value'])) {
31 | return $this->params['value'];
32 | }
33 |
34 | return $this->params;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/LoadAnnotationService.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\DependencyInjection\Compiler;
13 |
14 | use Nzo\UrlEncryptorBundle\Annotations\AnnotationResolver;
15 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16 | use Symfony\Component\DependencyInjection\ContainerBuilder;
17 |
18 | class LoadAnnotationService implements CompilerPassInterface
19 | {
20 | public function process(ContainerBuilder $container): void
21 | {
22 | $container
23 | ->register('nzo.annotation_resolver', AnnotationResolver::class)
24 | ->addArgument($container->getDefinition('nzo_encryptor'))
25 | ->addArgument($container->has('annotations.reader') ? $container->getDefinition('annotations.reader') : null)
26 | ->addTag('kernel.event_listener', ['event' => 'kernel.controller', 'method' => 'onKernelController'])
27 | ;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\DependencyInjection;
13 |
14 | use Symfony\Component\Config\Definition\Builder\TreeBuilder;
15 | use Symfony\Component\Config\Definition\ConfigurationInterface;
16 |
17 | class Configuration implements ConfigurationInterface
18 | {
19 | public function getConfigTreeBuilder(): TreeBuilder
20 | {
21 | $treeBuilder = new TreeBuilder('nzo_encryptor');
22 |
23 | $treeBuilder
24 | ->getRootNode()
25 | ->children()
26 | ->scalarNode('secret_key')
27 | ->isRequired()
28 | ->cannotBeEmpty()
29 | ->end()
30 | ->scalarNode('secret_iv')
31 | ->defaultValue('')
32 | ->end()
33 | ->scalarNode('cipher_algorithm')
34 | ->defaultValue('aes-256-ctr')
35 | ->end()
36 | ->booleanNode('base64_encode')
37 | ->defaultValue(true)
38 | ->end()
39 | ->booleanNode('format_base64_output')
40 | ->defaultValue(true)
41 | ->end()
42 | ->booleanNode('random_pseudo_bytes')
43 | ->defaultValue(true)
44 | ->end()
45 | ->end();
46 |
47 | return $treeBuilder;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/DependencyInjection/NzoEncryptorExtension.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\DependencyInjection;
13 |
14 | use Symfony\Component\Config\FileLocator;
15 | use Symfony\Component\DependencyInjection\ContainerBuilder;
16 | use Symfony\Component\DependencyInjection\Extension\Extension;
17 | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
18 |
19 | class NzoEncryptorExtension extends Extension
20 | {
21 | private const MAX_LENGTH = 100;
22 |
23 | public function load(array $configs, ContainerBuilder $container): void
24 | {
25 | $configuration = new Configuration();
26 | $config = $this->processConfiguration($configuration, $configs);
27 |
28 | $cipherAlgorithm = $config['cipher_algorithm'];
29 | if (!\in_array($cipherAlgorithm, openssl_get_cipher_methods(true), true)) {
30 | throw new \InvalidArgumentException("NzoEncryptor: Unknown cipher algorithm {$cipherAlgorithm}");
31 | }
32 |
33 | if (false === (bool) $config['random_pseudo_bytes'] && empty($config['secret_iv'])) {
34 | throw new \InvalidArgumentException("NzoEncryptor: 'secret_iv' cannot be empty when 'random_pseudo_bytes' is set to FALSE !");
35 | }
36 |
37 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
38 | $loader->load('services.yaml');
39 |
40 | $container->setParameter('nzo_encryptor.secret_key', $this->cleanKey($config['secret_key']));
41 | $container->setParameter('nzo_encryptor.secret_iv', $this->cleanKey($config['secret_iv']));
42 | $container->setParameter('nzo_encryptor.cipher_algorithm', $cipherAlgorithm);
43 | $container->setParameter('nzo_encryptor.base64_encode', (bool) $config['base64_encode']);
44 | $container->setParameter('nzo_encryptor.format_base64_output', (bool) $config['format_base64_output']);
45 | $container->setParameter('nzo_encryptor.random_pseudo_bytes', (bool) $config['random_pseudo_bytes']);
46 | }
47 |
48 | private function cleanKey(?string $key = null): string
49 | {
50 | if (null === $key || '' === $key || '0' === $key) {
51 | return '';
52 | }
53 |
54 | $key = trim($key);
55 | if (strlen($key) > self::MAX_LENGTH) {
56 | $key = substr($key, 0, self::MAX_LENGTH);
57 | }
58 |
59 | return $key;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Encryptor/Encryptor.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\Encryptor;
13 |
14 | class Encryptor
15 | {
16 | private const HASH_ALGORITHM = 'sha256';
17 |
18 | private $secretKey;
19 | private $cipherAlgorithm;
20 | private $base64Encode;
21 | private $formatBase64Output;
22 | private $randomPseudoBytes;
23 | private $iv;
24 |
25 | public function __construct(
26 | string $secretKey,
27 | string $cipherAlgorithm,
28 | bool $base64Encode,
29 | bool $formatBase64Output,
30 | bool $randomPseudoBytes
31 | ) {
32 | $this->secretKey = $secretKey;
33 | $this->cipherAlgorithm = $cipherAlgorithm;
34 | $this->base64Encode = $base64Encode;
35 | $this->formatBase64Output = $formatBase64Output;
36 | $this->randomPseudoBytes = $randomPseudoBytes;
37 | }
38 |
39 | /**
40 | * @param string $secretIv
41 | */
42 | public function setSecretIv($secretIv)
43 | {
44 | $ivLength = openssl_cipher_iv_length($this->cipherAlgorithm);
45 | $secretIv = $this->randomPseudoBytes ? openssl_random_pseudo_bytes($ivLength) : $secretIv;
46 |
47 | $this->iv = substr(
48 | hash_hmac(self::HASH_ALGORITHM, $secretIv, $this->secretKey, true),
49 | 0,
50 | $ivLength
51 | );
52 | }
53 |
54 | /**
55 | * @param string $plainText
56 | *
57 | * @return string
58 | */
59 | public function encrypt($plainText)
60 | {
61 | $encrypted = openssl_encrypt($plainText, $this->cipherAlgorithm, $this->secretKey, OPENSSL_RAW_DATA, $this->iv);
62 | $encrypted = $this->iv . $encrypted;
63 |
64 | return $this->base64Encode ? $this->base64Encode($encrypted) : $encrypted;
65 | }
66 |
67 | /**
68 | * @param string $encrypted
69 | *
70 | * @return string
71 | */
72 | public function decrypt($encrypted)
73 | {
74 | $ivLength = openssl_cipher_iv_length($this->cipherAlgorithm);
75 | $encrypted = $this->base64Encode ? $this->base64Decode($encrypted) : $encrypted;
76 | $iv = substr($encrypted, 0, $ivLength);
77 | $raw = substr($encrypted, $ivLength);
78 |
79 | $decrypted = openssl_decrypt(
80 | $raw,
81 | $this->cipherAlgorithm,
82 | $this->secretKey,
83 | OPENSSL_RAW_DATA,
84 | $iv
85 | );
86 |
87 | return trim($decrypted);
88 | }
89 |
90 | /**
91 | * @param string $data
92 | *
93 | * @return string
94 | */
95 | private function base64Encode($data)
96 | {
97 | if ($this->formatBase64Output) {
98 | return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
99 | }
100 |
101 | return base64_encode($data);
102 | }
103 |
104 | /**
105 | * @param string $data
106 | *
107 | * @return string
108 | */
109 | private function base64Decode($data)
110 | {
111 | if ($this->formatBase64Output) {
112 | return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT), true);
113 | }
114 |
115 | return base64_decode($data, true);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Ala Eddine khefifi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/NzoUrlEncryptorBundle.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle;
13 |
14 | use Nzo\UrlEncryptorBundle\DependencyInjection\Compiler\LoadAnnotationService;
15 | use Nzo\UrlEncryptorBundle\DependencyInjection\NzoEncryptorExtension;
16 | use Symfony\Component\DependencyInjection\ContainerBuilder;
17 | use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
18 | use Symfony\Component\HttpKernel\Bundle\Bundle;
19 |
20 | class NzoUrlEncryptorBundle extends Bundle
21 | {
22 | public function getContainerExtension(): ?ExtensionInterface
23 | {
24 | return new NzoEncryptorExtension();
25 | }
26 |
27 | public function build(ContainerBuilder $container): void
28 | {
29 | $container->addCompilerPass(new LoadAnnotationService());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | NzoUrlEncryptorBundle
2 | =====================
3 |
4 | [](https://github.com/nayzo/NzoUrlEncryptorBundle/actions/workflows/tests.yaml)
5 | [](https://packagist.org/packages/nzo/url-encryptor-bundle)
6 | [](https://packagist.org/packages/nzo/url-encryptor-bundle)
7 |
8 | The **NzoUrlEncryptorBundle** is a Symfony Bundle used to Encrypt and Decrypt data and variables in the Web application or passed through the ``URL`` to provide more security to the project.
9 | Also it prevent users from reading and modifying sensitive data sent through the ``URL``.
10 |
11 |
12 | #### The Version (^6.0) is compatible with **Symfony >= 4.4**
13 |
14 |
15 | Features include:
16 |
17 | - Url Data & parameters Encryption
18 | - Url Data & parameters Decryption
19 | - Data Encryption & Decryption
20 | - Access from Twig by ease
21 | - Flexible configuration
22 | - Uses OpenSSL extension
23 |
24 |
25 | By default, this bundle use the **aes-256-ctr** algorithm.
26 |
27 | CTR mode (without any additional authentication step) is malleable, which means that it is possible to change the meaning of the ciphertext and if the plaintext is guessable then it could lead to IDOR.
28 |
29 | ##### For more secure output, you must configure the bundle to use a **unique and random IV** (`random_pseudo_bytes: TRUE`)
30 |
31 |
32 | Installation
33 | ------------
34 |
35 | ### Through Composer:
36 |
37 | Install the bundle:
38 |
39 | ```
40 | $ composer require nzo/url-encryptor-bundle
41 | ```
42 |
43 | ### Register the bundle in config/bundles.php (without Flex):
44 |
45 | ``` php
46 | // config/bundles.php
47 |
48 | return [
49 | // ...
50 | Nzo\UrlEncryptorBundle\NzoUrlEncryptorBundle::class => ['all' => true],
51 | ];
52 | ```
53 |
54 | ### Configure the bundle:
55 |
56 | ``` yml
57 | # config/packages/nzo_encryptor.yaml
58 |
59 | nzo_encryptor:
60 | secret_key: Your_Secret_Encryption_Key # Required, max length of 100 characters.
61 | secret_iv: Your_Secret_Iv # Required only if "random_pseudo_bytes" is FALSE. Max length of 100 characters.
62 | cipher_algorithm: # optional, default: 'aes-256-ctr'
63 | base64_encode: # optional, default: TRUE
64 | format_base64_output: # optional, default: TRUE, used only when 'base64_encode' is set to TRUE
65 | random_pseudo_bytes: # optional, default: TRUE (generate a random encrypted text output each time => MORE SECURE !)
66 | ```
67 |
68 | ##### * To generate the same cypher text each time: `random_pseudo_bytes: FALSE` (Not Secure)
69 | ##### * To generate a different cypher text each time: `random_pseudo_bytes: TRUE` (Secure)
70 |
71 | Usage
72 | -----
73 |
74 | #### In the twig template:
75 |
76 | Use the twig extensions filters or functions to ``encrypt`` or ``decrypt`` your data:
77 |
78 | ``` html
79 | // Filters:
80 |
81 | # Encryption:
82 |
83 | My link
84 |
85 | {{myVar | nzo_encrypt }}
86 |
87 | # Decryption:
88 |
89 | My link
90 |
91 | {{myVar | nzo_decrypt }}
92 |
93 |
94 | // Functions:
95 |
96 | # Encryption:
97 |
98 | My link
99 |
100 | {{ nzo_encrypt(myVar) }}
101 |
102 | # Decryption:
103 |
104 | My link
105 |
106 | {{ nzo_decrypt(myVar) }}
107 | ```
108 |
109 | #### In the controller with annotation service:
110 |
111 | Use the annotation service to ``decrypt`` / ``encrypt`` automatically any parameter you want, by using the ``ParamDecryptor`` / ``ParamEncryptor`` annotation service and specifying in it all the parameters to be decrypted/encrypted.
112 |
113 | ```php
114 | use Nzo\UrlEncryptorBundle\Annotations\ParamDecryptor;
115 | use Nzo\UrlEncryptorBundle\Annotations\ParamEncryptor;
116 |
117 | class MyController
118 | {
119 | /**
120 | * @ParamDecryptor({"id", "foo"})
121 | */
122 | // OR
123 | #[ParamDecryptor(["id", "foo"])]
124 | public function decryptionAction($id, $foo)
125 | {
126 | // no need to use the decryption service here as the parameters are already decrypted by the annotation service.
127 | //...
128 | }
129 |
130 | /**
131 | * @ParamEncryptor({"id", "foo"})
132 | */
133 | // OR
134 | #[ParamEncryptor(["id", "foo"])]
135 | public function encryptionAction($id, $foo)
136 | {
137 | // no need to use the encryption service here as the parameters are already encrypted by the annotation service.
138 | //...
139 | }
140 | }
141 | ```
142 |
143 | #### With autowiring:
144 |
145 | ```php
146 | use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
147 |
148 | class MyController
149 | {
150 | private $encryptor;
151 |
152 | public function __construct(Encryptor $encryptor)
153 | {
154 | $this->encryptor = $encryptor;
155 | }
156 |
157 | public function indexAction($data)
158 | {
159 | $encrypted = $this->encryptor->encrypt($data);
160 |
161 | $decrypted = $this->encryptor->decrypt($data);
162 | }
163 | }
164 | ```
165 |
166 | #### Without autowiring:
167 |
168 | ```php
169 | class MyController
170 | {
171 | public function indexAction($data)
172 | {
173 | $encrypted = $this->get('nzo_encryptor')->encrypt($data);
174 |
175 | $decrypted = $this->get('nzo_encryptor')->decrypt($data);
176 | }
177 | }
178 | ```
179 |
180 | License
181 | -------
182 |
183 | This bundle is under the MIT license. See the complete license in the bundle:
184 |
185 | See [LICENSE](https://github.com/nayzo/NzoUrlEncryptorBundle/tree/master/LICENSE)
186 |
--------------------------------------------------------------------------------
/Resources/config/services.yaml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | Nzo\UrlEncryptorBundle\Encryptor\Encryptor: "@nzo_encryptor"
4 |
5 | nzo_encryptor:
6 | class: Nzo\UrlEncryptorBundle\Encryptor\Encryptor
7 | arguments:
8 | - "%nzo_encryptor.secret_key%"
9 | - "%nzo_encryptor.cipher_algorithm%"
10 | - "%nzo_encryptor.base64_encode%"
11 | - "%nzo_encryptor.format_base64_output%"
12 | - "%nzo_encryptor.random_pseudo_bytes%"
13 | calls:
14 | - [setSecretIv, ["%nzo_encryptor.secret_iv%"]]
15 |
16 | nzo.twig.encryptor_extension:
17 | class: Nzo\UrlEncryptorBundle\Twig\EncryptorExtension
18 | arguments:
19 | - "@nzo_encryptor"
20 | tags:
21 | - { name: twig.extension }
22 |
--------------------------------------------------------------------------------
/Tests/Annotation/AnnotationResolverTest.php:
--------------------------------------------------------------------------------
1 | markTestSkipped('At least PHP 8 is needed for this test');
29 | }
30 |
31 | $encryptor = new Encryptor('foo', 'aes-256-ctr', true, true, true);
32 | $encryptor->setSecretIv('secret');
33 |
34 | $request = Request::create('/');
35 | $request->attributes->set('id', $encryptor->encrypt('some_data'));
36 |
37 | $controllerEvent = new ControllerEvent(
38 | $this->createMock(HttpKernelInterface::class),
39 | [new DummyController(), $action],
40 | $request,
41 | 1
42 | );
43 |
44 | $sut = new AnnotationResolver($encryptor, new AnnotationReader());
45 | $sut->onKernelController($controllerEvent);
46 |
47 | $this->assertSame('some_data', $request->attributes->get('id'));
48 | }
49 |
50 | public function provideEncryptOnKernelController(): \Iterator
51 | {
52 | yield ['encryptWithAttribute', true];
53 | yield ['encryptWithAnnotation', false];
54 | }
55 |
56 | /**
57 | * @dataProvider provideEncryptOnKernelController
58 | */
59 | public function testEncryptOnKernelController(string $action, bool $needsPhp8): void
60 | {
61 | if ($needsPhp8 && PHP_VERSION_ID < 80000) {
62 | $this->markTestSkipped('At least PHP 8 is needed for this test');
63 | }
64 |
65 | $encryptor = new Encryptor('foo', 'aes-256-ctr', true, true, true);
66 | $encryptor->setSecretIv('secret');
67 |
68 | $request = Request::create('/');
69 | $request->attributes->set('id', 'some_data');
70 |
71 | $controllerEvent = new ControllerEvent(
72 | $this->createMock(HttpKernelInterface::class),
73 | [new DummyController(), $action],
74 | $request,
75 | 1
76 | );
77 |
78 | $sut = new AnnotationResolver($encryptor, new AnnotationReader());
79 | $sut->onKernelController($controllerEvent);
80 |
81 | $this->assertSame($encryptor->encrypt('some_data'), $request->attributes->get('id'));
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Tests/Annotation/Fixtures/DummyController.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\Tests\Encryptor;
13 |
14 | use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | class NzoEncryptorExtensionTest extends TestCase
18 | {
19 | public const CIPHER_ALGORITHM = 'aes-256-ctr';
20 | public const PLAIN_TEXT = 'plain_text';
21 | public const SECRET_KEY = 'encryptionKeyText';
22 | public const SECRET_IV = 'encryptionIvText';
23 | public const BASE64_ENCODE = true;
24 | public const FORMAT_BASE64_OUTPUT = true;
25 | public const RANDOM_PSEUDO_BYTES = false;
26 |
27 | private $encryptor;
28 |
29 | public function setup(): void
30 | {
31 | $this->encryptor = new Encryptor(
32 | self::SECRET_KEY,
33 | self::CIPHER_ALGORITHM,
34 | self::BASE64_ENCODE,
35 | self::FORMAT_BASE64_OUTPUT,
36 | self::RANDOM_PSEUDO_BYTES
37 | );
38 |
39 | $this->encryptor->setSecretIv(self::SECRET_IV);
40 | }
41 |
42 | public function testEncrypt()
43 | {
44 | $encrypted = $this->encryptor->encrypt(self::PLAIN_TEXT);
45 | $decrypted = $this->encryptor->decrypt($encrypted);
46 |
47 | $this->assertSame(self::PLAIN_TEXT, $decrypted);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Twig/EncryptorExtension.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Nzo\UrlEncryptorBundle\Twig;
13 |
14 | use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
15 | use Twig\Extension\AbstractExtension;
16 | use Twig\TwigFilter;
17 | use Twig\TwigFunction;
18 |
19 | class EncryptorExtension extends AbstractExtension
20 | {
21 | private $encryptor;
22 |
23 | public function __construct(Encryptor $encryptor)
24 | {
25 | $this->encryptor = $encryptor;
26 | }
27 |
28 | public function getFilters(): array
29 | {
30 | return [
31 | new TwigFilter('nzo_encrypt', [$this, 'encryptFilter']),
32 | new TwigFilter('nzo_decrypt', [$this, 'decryptFilter']),
33 | ];
34 | }
35 |
36 | public function getFunctions(): array
37 | {
38 | return [
39 | new TwigFunction('nzo_encrypt', [$this, 'encryptFunction']),
40 | new TwigFunction('nzo_decrypt', [$this, 'decryptFunction']),
41 | ];
42 | }
43 |
44 | /**
45 | * @param string $key
46 | *
47 | * @return string
48 | */
49 | public function encryptFilter($key)
50 | {
51 | return $this->encryptor->encrypt($key);
52 | }
53 |
54 | /**
55 | * @param string $key
56 | *
57 | * @return string
58 | */
59 | public function decryptFilter($key)
60 | {
61 | return $this->encryptor->decrypt($key);
62 | }
63 |
64 | /**
65 | * @param string $key
66 | *
67 | * @return string
68 | */
69 | public function encryptFunction($key)
70 | {
71 | return $this->encryptor->encrypt($key);
72 | }
73 |
74 | /**
75 | * @param string $key
76 | *
77 | * @return string
78 | */
79 | public function decryptFunction($key)
80 | {
81 | return $this->encryptor->decrypt($key);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nzo/url-encryptor-bundle",
3 | "type": "symfony-bundle",
4 | "description": "The NzoUrlEncryptorBundle is a Symfony Bundle used to Encrypt and Decrypt data and variables in the Web application or passed through URL",
5 | "keywords": ["Link", "url", "encryption", "decryption", "encrypt", "decrypt", "id", "data", "variable", "security", "AES"],
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Ala Eddine Khefifi",
10 | "email": "alakfpro@gmail.com"
11 | }
12 | ],
13 | "autoload": {
14 | "psr-4": {
15 | "Nzo\\UrlEncryptorBundle\\": ""
16 | },
17 | "exclude-from-classmap": [
18 | "/Tests/"
19 | ]
20 | },
21 | "require": {
22 | "php": ">=7.1.3",
23 | "ext-openssl": "*",
24 | "symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0 || ^7.0"
25 | },
26 | "suggest": {
27 | "doctrine/annotations": "Required for annotation support, compatible with versions ^1.7 || ^2.0",
28 | "twig/twig": "Required for twig nzo_encrypt and nzo_decrypt functions support"
29 | },
30 | "require-dev": {
31 | "doctrine/annotations": "^1.7 || ^2.0",
32 | "friendsofphp/php-cs-fixer": "^2.2 || ^3.68",
33 | "rector/rector": "*",
34 | "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
35 | "phpstan/phpstan": "^1.0 || ^2.0"
36 | },
37 | "config": {
38 | "sort-packages": true
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 5
3 | excludePaths:
4 | - vendor/*
5 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ./Tests/
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/rector.php:
--------------------------------------------------------------------------------
1 | paths([__DIR__]);
13 | $rectorConfig->skip([__DIR__ . '/vendor', __DIR__ . '/.github']);
14 |
15 | $rectorConfig->phpVersion(PhpVersion::PHP_71);
16 |
17 | $rectorConfig->importNames();
18 | $rectorConfig->importShortClasses(false);
19 |
20 | $rectorConfig->rule(AddParamTypeFromPropertyTypeRector::class);
21 | $rectorConfig->rule(AddParamTypeDeclarationRector::class);
22 |
23 | $rectorConfig->sets([
24 | SetList::PHP_71,
25 | SetList::CODE_QUALITY,
26 | SymfonySetList::SYMFONY_54,
27 | SymfonySetList::SYMFONY_64,
28 | SymfonySetList::CONFIGS,
29 | SymfonySetList::SYMFONY_CODE_QUALITY,
30 | SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
31 | PHPUnitSetList::PHPUNIT_90,
32 | PHPUnitSetList::PHPUNIT_CODE_QUALITY,
33 | ]);
34 | };
35 |
--------------------------------------------------------------------------------