forked from ambta/DoctrineEncryptBundle
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDoctrineDecryptDatabaseCommand.php
More file actions
158 lines (130 loc) · 6.39 KB
/
DoctrineDecryptDatabaseCommand.php
File metadata and controls
158 lines (130 loc) · 6.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?php
namespace Ambta\DoctrineEncryptBundle\Command;
use Ambta\DoctrineEncryptBundle\DependencyInjection\DoctrineEncryptExtension;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Decrypt whole database on tables which are encrypted.
*
* @author Marcel van Nuil <marcel@ambta.com>
* @author Michael Feinbier <michael@feinbier.net>
*/
class DoctrineDecryptDatabaseCommand extends AbstractCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('doctrine:decrypt:database')
->setDescription('Decrypt whole database on tables which are encrypted')
->addArgument('encryptor', InputArgument::OPTIONAL, 'The encryptor you want to decrypt the database with')
->addArgument('batchSize', InputArgument::OPTIONAL, 'The update/flush batch size', 20);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
//Get entity manager, question helper, subscriber service and annotation reader
$question = $this->getHelper('question');
//Get list of supported encryptors
$supportedExtensions = DoctrineEncryptExtension::$supportedEncryptorClasses;
$batchSize = $input->getArgument('batchSize');
//If encryptor has been set use that encryptor else use default
if ($input->getArgument('encryptor')) {
if (isset($supportedExtensions[$input->getArgument('encryptor')])) {
$this->subscriber->setEncryptor($supportedExtensions[$input->getArgument('encryptor')]);
} else {
if (class_exists($input->getArgument('encryptor'))) {
$this->subscriber->setEncryptor($input->getArgument('encryptor'));
} else {
$output->writeln('\nGiven encryptor does not exists');
$output->writeln('Supported encryptors: '.implode(', ', array_keys($supportedExtensions)));
$output->writeln('You can also define your own class. (example: \Ambta\DoctrineEncryptBundle\Encryptors\AES256Encryptor)');
return;
}
}
}
//Get entity manager metadata
$metaDataArray = $this->entityManager->getMetadataFactory()->getAllMetadata();
//Set counter and loop through entity manager meta data
$propertyCount = 0;
foreach ($metaDataArray as $metaData) {
if ($metaData->isMappedSuperclass) {
continue;
}
$countProperties = count($this->getEncryptionableProperties($metaData));
$propertyCount += $countProperties;
}
$confirmationQuestion = new ConfirmationQuestion(
"<question>\n".count($metaDataArray).' entities found which are containing '.$propertyCount." properties with the encryption tag. \n\n".
'Which are going to be decrypted with ['.$this->subscriber->getEncryptor()."]. \n\n".
"Wrong settings can mess up your data and it will be unrecoverable. \n".
"I advise you to make <bg=yellow;options=bold>a backup</bg=yellow;options=bold>. \n\n".
'Continue with this action? (y/yes)</question>', false
);
if (!$question->ask($input, $output, $confirmationQuestion)) {
return;
}
//Start decrypting database
$output->writeln("\nDecrypting all fields. This can take up to several minutes depending on the database size.");
$valueCounter = 0;
//Loop through entity manager meta data
foreach ($this->getEncryptionableEntityMetaData() as $metaData) {
$i = 0;
$iterator = $this->getEntityIterator($metaData->name);
$totalCount = $this->getTableCount($metaData->name);
$output->writeln(sprintf('Processing <comment>%s</comment>', $metaData->name));
$progressBar = new ProgressBar($output, $totalCount);
foreach ($iterator as $row) {
$entity = $row[0];
//Create reflectionClass for each entity
$entityReflectionClass = new \ReflectionClass($entity);
//Get the current encryptor used
$encryptorUsed = $this->subscriber->getEncryptor();
//Loop through the property's in the entity
foreach ($this->getEncryptionableProperties($metaData) as $property) {
//Get and check getters and setters
$methodeName = ucfirst($property->getName());
$getter = 'get'.$methodeName;
$setter = 'set'.$methodeName;
//Check if getter and setter are set
if ($entityReflectionClass->hasMethod($getter) && $entityReflectionClass->hasMethod($setter)) {
//Get decrypted data
$unencrypted = $entity->$getter();
//Set raw data
$entity->$setter($unencrypted);
++$valueCounter;
}
}
//Disable the encryptor
$this->subscriber->setEncryptor(null);
$this->entityManager->persist($entity);
if (($i % $batchSize) === 0) {
$this->entityManager->flush();
$this->entityManager->clear();
}
$progressBar->advance(1);
++$i;
//Set the encryptor again
$this->subscriber->setEncryptor($encryptorUsed);
}
$progressBar->finish();
$output->writeln('');
//Get the current encryptor used
$encryptorUsed = $this->subscriber->getEncryptor();
$this->subscriber->setEncryptor(null);
$this->entityManager->flush();
$this->entityManager->clear();
//Set the encryptor again
$this->subscriber->setEncryptor($encryptorUsed);
}
//Say it is finished
$output->writeln("\nDecryption finished values found: <info>".$valueCounter.'</info>, decrypted: <info>'.$this->subscriber->decryptCounter."</info>.\nAll values are now decrypted.");
}
}