Skip to content

Commit f3f0ff4

Browse files
committed
Add a enabler to allow values to not be decrypted or encrypted temporary
1 parent 272ca6b commit f3f0ff4

File tree

11 files changed

+283
-59
lines changed

11 files changed

+283
-59
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,35 @@ key which can prove to be tricky, especially if users already have accounts and
6161

6262
If each user encrypts it's own data however, you can just use the automatic encryption key generation in your
6363
config.yml:
64-
```
64+
```yaml
6565
sidus_encryption:
6666
encryption_key:
6767
auto_generate: false
68+
throw_exceptions: true # Do not throw an exception when an error occurred when decrypting a value
6869
```
6970
This will tell the system to automatically generate a new encryption key if the user doesn't have any.
7071
7172
In case of password recovery, the user won't be able to retrieve any of the encrypted data because he would be the only
7273
one able to decrypt the cipher key.
7374
75+
Disable Encryption
76+
------------------
77+
The encryption can be temporary disabled on an encrypted type (in a command for example). This can be achieved using
78+
the `Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface` service:
79+
```php
80+
81+
// ...
82+
$encryptionEnabler->disableEncryption();
83+
84+
// Starting from here, data will not be decrypted
85+
$encryptionManager->decryptString($value); // The value will not be decrypted
86+
$encryptionManager->encryptString($value); // The value will not be encrypted and store as is
87+
88+
$encryptionEnabler->enableEncryption();
89+
// Now the encryption is re-enabled and works normally
90+
91+
```
92+
7493
Apache License
7594
--------------
7695
@todo

src/Doctrine/Connection/Factory/ConnectionFactory.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Doctrine\DBAL\Platforms\AbstractPlatform;
1212
use Doctrine\DBAL\Types\Type;
1313
use Sidus\EncryptionBundle\Doctrine\Type\EncryptTypeInterface;
14+
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
1415
use Sidus\EncryptionBundle\Registry\EncryptionManagerRegistry;
1516

1617
/**
@@ -22,20 +23,27 @@ class ConnectionFactory
2223
private bool $initialized = false;
2324

2425
private EncryptionManagerRegistry $encryptionManager;
25-
26-
public function __construct(array $typesConfig, EncryptionManagerRegistry $encryptionManager)
27-
{
26+
private EncryptionEnablerInterface $encryptionEnabler;
27+
28+
public function __construct(
29+
array $typesConfig,
30+
EncryptionManagerRegistry $encryptionManager,
31+
EncryptionEnablerInterface $encryptionEnabler
32+
) {
2833
$this->typesConfig = $typesConfig;
2934
$this->encryptionManager = $encryptionManager;
35+
$this->encryptionEnabler = $encryptionEnabler;
3036
}
31-
37+
3238
/**
3339
* Create a connection by name.
3440
*
3541
* @param mixed[] $params
3642
* @param string[]|Type[] $mappingTypes
3743
*
3844
* @return Connection
45+
*
46+
* @throws \Doctrine\DBAL\Exception
3947
*/
4048
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = []): Connection
4149
{
@@ -129,6 +137,7 @@ private function initializeTypes() : void
129137

130138
if ($type instanceof EncryptTypeInterface) {
131139
$type->setEncryptionManager($this->encryptionManager->getDefaultEncryptionManager());
140+
$type->setEncryptionEnabler($this->encryptionEnabler);
132141
}
133142
}
134143
$this->initialized = true;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Sidus\EncryptionBundle\Doctrine\Type\Behavior;
4+
5+
use Doctrine\DBAL\Platforms\AbstractPlatform;
6+
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
7+
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
8+
9+
trait EncryptType
10+
{
11+
private EncryptionManagerInterface $encryptionManager;
12+
private EncryptionEnablerInterface $encryptionEnabler;
13+
14+
public function convertToPHPValue($value, AbstractPlatform $platform)
15+
{
16+
// Allow to do not decrypt the value for the current request
17+
if (!$this->encryptionEnabler->isEncryptionEnabled()) {
18+
return $value;
19+
}
20+
21+
return $this->encryptionManager->decryptString(base64_decode($value));
22+
}
23+
24+
public function convertToDatabaseValue($value, AbstractPlatform $platform)
25+
{
26+
// Allow to do not decrypt the value for the current request
27+
if (!$this->encryptionEnabler->isEncryptionEnabled()) {
28+
return $value;
29+
}
30+
$value = $this->encryptionManager->encryptString($value);
31+
32+
return base64_encode($value);
33+
}
34+
35+
public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void
36+
{
37+
$this->encryptionManager = $encryptionManager;
38+
}
39+
40+
public function setEncryptionEnabler(EncryptionEnablerInterface $encryptionEnabler): void
41+
{
42+
$this->encryptionEnabler = $encryptionEnabler;
43+
}
44+
}

src/Doctrine/Type/EncryptStringType.php

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,14 @@
22

33
namespace Sidus\EncryptionBundle\Doctrine\Type;
44

5-
use Doctrine\DBAL\Platforms\AbstractPlatform;
65
use Doctrine\DBAL\Types\StringType;
7-
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
6+
use Sidus\EncryptionBundle\Doctrine\Type\Behavior\EncryptType;
87

98
class EncryptStringType extends StringType implements EncryptTypeInterface
109
{
11-
private EncryptionManagerInterface $encryptionManager;
10+
use EncryptType;
1211

13-
public function convertToPHPValue($value, AbstractPlatform $platform)
14-
{
15-
$value = base64_decode($value);
16-
17-
return $this->encryptionManager->decryptString($value);
18-
}
19-
20-
public function convertToDatabaseValue($value, AbstractPlatform $platform)
21-
{
22-
$value = $this->encryptionManager->encryptString($value);
23-
24-
return base64_encode($value);
25-
}
26-
27-
public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void
28-
{
29-
$this->encryptionManager = $encryptionManager;
30-
}
31-
32-
public function getName()
12+
public function getName(): string
3313
{
3414
return 'encrypt_string';
3515
}

src/Doctrine/Type/EncryptTextType.php

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,12 @@
22

33
namespace Sidus\EncryptionBundle\Doctrine\Type;
44

5-
use Doctrine\DBAL\Platforms\AbstractPlatform;
65
use Doctrine\DBAL\Types\TextType;
7-
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
6+
use Sidus\EncryptionBundle\Doctrine\Type\Behavior\EncryptType;
87

98
class EncryptTextType extends TextType implements EncryptTypeInterface
109
{
11-
private EncryptionManagerInterface $encryptionManager;
12-
13-
public function convertToPHPValue($value, AbstractPlatform $platform)
14-
{
15-
$value = base64_decode($value);
16-
17-
return $this->encryptionManager->decryptString($value);
18-
}
19-
20-
public function convertToDatabaseValue($value, AbstractPlatform $platform)
21-
{
22-
$value = $this->encryptionManager->encryptString($value);
23-
24-
return base64_encode($value);
25-
}
26-
27-
public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void
28-
{
29-
$this->encryptionManager = $encryptionManager;
30-
}
10+
use EncryptType;
3111

3212
public function getName()
3313
{

src/Doctrine/Type/EncryptTypeInterface.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
namespace Sidus\EncryptionBundle\Doctrine\Type;
44

5+
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
56
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
67

78
interface EncryptTypeInterface
89
{
910
public function setEncryptionManager(EncryptionManagerInterface $encryptionManager): void;
11+
12+
public function setEncryptionEnabler(EncryptionEnablerInterface $encryptionEnabler): void;
1013
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Sidus\EncryptionBundle\Encryption\Enabler;
4+
5+
class EncryptionEnabler implements EncryptionEnablerInterface
6+
{
7+
/**
8+
* By default the encryption is enabled.
9+
*
10+
* @var bool
11+
*/
12+
private bool $enabled = true;
13+
14+
public function enableEncryption(): void
15+
{
16+
$this->enabled = true;
17+
}
18+
19+
public function disableEncryption(): void
20+
{
21+
$this->enabled = false;
22+
}
23+
24+
public function isEncryptionEnabled(): bool
25+
{
26+
return $this->enabled;
27+
}
28+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Sidus\EncryptionBundle\Encryption\Enabler;
4+
5+
interface EncryptionEnablerInterface
6+
{
7+
/**
8+
* Enable the encryption for the current request.
9+
*/
10+
public function enableEncryption(): void;
11+
12+
/**
13+
* Disable the encryption for the current request.
14+
*/
15+
public function disableEncryption(): void;
16+
17+
/**
18+
* Return if the encryption is enabled in the current request.
19+
*
20+
* @return bool
21+
*/
22+
public function isEncryptionEnabled(): bool;
23+
}

src/Resources/config/services/encryption.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ services:
1616
public: false
1717
tags:
1818
- { name: sidus.encryption.adapter }
19+
20+
Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnabler:
21+
class: Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnabler
22+
public: false

tests/PHPUnit/Doctrine/Type/EncryptStringTypeTest.php

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,23 @@
66
use PHPUnit\Framework\MockObject\MockObject;
77
use PHPUnit\Framework\TestCase;
88
use Sidus\EncryptionBundle\Doctrine\Type\EncryptStringType;
9+
use Sidus\EncryptionBundle\Encryption\Enabler\EncryptionEnablerInterface;
910
use Sidus\EncryptionBundle\Manager\EncryptionManagerInterface;
1011

1112
class EncryptStringTypeTest extends TestCase
1213
{
1314
public function testConvertToPHPValue(): void
1415
{
15-
[$type, $encryptionManager] = $this->createType();
16+
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
1617
$encryptedString = '\X666';
1718
$platform = $this->createMock(MySqlPlatform::class);
1819

20+
$encryptionEnabler
21+
->expects($this->once())
22+
->method('isEncryptionEnabled')
23+
->willReturn(true)
24+
;
25+
1926
// The type SHOULD decrypt the encrypted string
2027
$encryptionManager
2128
->expects($this->once())
@@ -28,12 +35,40 @@ public function testConvertToPHPValue(): void
2835
$this->assertEquals('my_decrypted_string', $value);
2936
}
3037

38+
public function testConvertToPHPValueWithEncryptionDisabled(): void
39+
{
40+
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
41+
$encryptedString = '\X666';
42+
$platform = $this->createMock(MySqlPlatform::class);
43+
44+
$encryptionEnabler
45+
->expects($this->once())
46+
->method('isEncryptionEnabled')
47+
->willReturn(false)
48+
;
49+
50+
// The type SHOULD not encrypt the encrypted string if the encryption is disabled
51+
$encryptionManager
52+
->expects($this->never())
53+
->method('decryptString')
54+
;
55+
56+
$value = $type->convertToPHPValue($encryptedString, $platform);
57+
$this->assertEquals('\X666', $value);
58+
}
59+
3160
public function testConvertToDatabaseValue(): void
3261
{
33-
[$type, $encryptionManager] = $this->createType();
62+
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
3463
$string = 'my_string';
3564
$platform = $this->createMock(MySqlPlatform::class);
3665

66+
$encryptionEnabler
67+
->expects($this->once())
68+
->method('isEncryptionEnabled')
69+
->willReturn(true)
70+
;
71+
3772
// The type SHOULD decrypt the encrypted string
3873
$encryptionManager
3974
->expects($this->once())
@@ -46,15 +81,47 @@ public function testConvertToDatabaseValue(): void
4681
$this->assertEquals(base64_encode('my_encrypted_string'), $value);
4782
}
4883

84+
public function testConvertToDatabaseValueWithEncryptionDisabled(): void
85+
{
86+
[$type, $encryptionManager, $encryptionEnabler] = $this->createType();
87+
$string = 'my_string';
88+
$platform = $this->createMock(MySqlPlatform::class);
89+
90+
$encryptionEnabler
91+
->expects($this->once())
92+
->method('isEncryptionEnabled')
93+
->willReturn(false)
94+
;
95+
96+
// The type SHOULD not decrypt the encrypted string if the encryption is disabled
97+
$encryptionManager
98+
->expects($this->never())
99+
->method('encryptString')
100+
;
101+
102+
$value = $type->convertToDatabaseValue($string, $platform);
103+
$this->assertEquals('my_string', $value);
104+
}
105+
106+
public function testGetName(): void
107+
{
108+
[$type] = $this->createType();
109+
110+
$this->assertEquals('encrypt_string', $type->getName());
111+
}
112+
49113
/**
50114
* @return EncryptStringType[]|MockObject[]
51115
*/
52116
private function createType(): array
53117
{
54118
$encryptionManager = $this->createMock(EncryptionManagerInterface::class);
119+
$encryptionEnabler = $this->createMock(EncryptionEnablerInterface::class);
120+
55121
$type = new EncryptStringType();
56122
$type->setEncryptionManager($encryptionManager);
123+
$type->setEncryptionEnabler($encryptionEnabler);
57124

58-
return [$type, $encryptionManager];
125+
return [$type, $encryptionManager, $encryptionEnabler];
59126
}
60127
}

0 commit comments

Comments
 (0)