Passed
Push — master ( 71d23f...5a582b )
by Thomas
02:20
created

EncryptTest::testCompositeOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 18
rs 9.9666
cc 1
nc 1
nop 0
1
<?php
2
3
namespace LeKoala\Encrypt\Test;
4
5
use Exception;
6
use SilverStripe\Assets\File;
7
use SilverStripe\ORM\DataObject;
8
use SilverStripe\Security\Member;
9
use LeKoala\Encrypt\EncryptHelper;
10
use SilverStripe\Core\Environment;
11
use SilverStripe\Dev\SapphireTest;
12
use LeKoala\Encrypt\EncryptedDBField;
13
use LeKoala\Encrypt\HasEncryptedFields;
14
use ParagonIE\CipherSweet\CipherSweet;
15
use SilverStripe\ORM\DataList;
16
use SilverStripe\ORM\DB;
17
use SilverStripe\ORM\Queries\SQLSelect;
18
use SilverStripe\ORM\Queries\SQLUpdate;
19
20
/**
21
 * Test for Encrypt
22
 *
23
 * Run with the following command : ./vendor/bin/phpunit ./encrypt/tests/EncryptTest.php
24
 *
25
 * You may need to run:
26
 * php ./framework/cli-script.php dev/build ?flush=all
27
 * before (remember manifest for cli is not the same...)
28
 *
29
 * @group Encrypt
30
 */
31
class EncryptTest extends SapphireTest
32
{
33
    /**
34
     * Defines the fixture file to use for this test class
35
     * @var string
36
     */
37
    protected static $fixture_file = 'EncryptTest.yml';
38
39
    protected static $extra_dataobjects = [
40
        Test_EncryptedModel::class,
41
    ];
42
43
    public function setUp()
44
    {
45
        // EncryptHelper::setForcedEncryption("nacl");
46
        EncryptHelper::setAutomaticRotation(false);
47
        Environment::setEnv('ENCRYPTION_KEY', '502370dfc69fd6179e1911707e8a5fb798c915900655dea16370d64404be04e5');
48
        parent::setUp();
49
        EncryptHelper::setAutomaticRotation(true);
50
51
        // test extension is available
52
        if (!extension_loaded('sodium')) {
53
            throw new Exception("You must load sodium extension for this");
54
        }
55
56
        // The rows are already decrypted and changed due to the fixtures going through the ORM layer
57
        $result = DB::query("SELECT * FROM EncryptedModel");
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
58
        // echo '<pre>';
59
        // print_r(iterator_to_array($result));
60
        // die();
61
62
        // Replace with actual yml values
63
        $data = [
64
            'MyText' => 'nacl:_nKhFvZkFwWJssMLf2s6wsucM-6zMmT862XGiYG9KQaL5fgl3CSA_O0gcs3OGPPB4AJoNInC',
65
            'MyHTMLText' => 'nacl:jetKPUBgETbLtlfAx1VkZiWJFG65hCuWVSmrwVDX4TTysmJkj2vnhI329oa9eCTlX1kKSjCp7AyFXDKT7Q==',
66
            'MyVarchar' => 'nacl:_-5ZsG9txfqMNkHY7xl0JlmCLzrx9BemtC0CwGjYZOt9pCwle9PjHmIZcqJcoEdxpJXplLtKPF-xPGax_pIy',
67
            'MyIndexedVarcharValue' => 'nacl:V1G-EPYeHP5-OQu2XAcPp4ym0HuvLpseBqytg3VVddAWoyC3Lm5aAE3G9xx_2uW6QwO0dcnrLFBPNFZ6eQ==',
68
            'MyNumberValue' => 'nacl:u4-luf5o0pi-LuGOwLvKVGgD_tLlO8YJ7GbIx4VYYcUvoPNM-9pQfv05iwb0HQ6ugW4=',
69
        ];
70
        $update = new SQLUpdate("EncryptedModel", $data, "ID IN (1,3)");
0 ignored issues
show
Bug introduced by
'ID IN (1,3)' of type string is incompatible with the type array expected by parameter $where of SilverStripe\ORM\Queries\SQLUpdate::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
        $update = new SQLUpdate("EncryptedModel", $data, /** @scrutinizer ignore-type */ "ID IN (1,3)");
Loading history...
71
        $update->execute();
72
        $data = [
73
            'MyText' => 'brng:DwBtLvR876mbL5qfX1IIUDZ7NbrDtyXAgXjB8dDKxfYAYKlajKr9J9NGMY47tkNcrLv4PBbHQ4bAOTZHGsTvmQuGT7he0w==',
74
            'MyHTMLText' => 'brng:Nf7VDpEPIQABaZvch8wDY3jCuctBcy0x6sIJO_BkWJL2H86b6O0WvXfDldFihhXxnhzJH3cy-Ygx6sMbgBttDPcT6j8SXFqxeG2pxHI=',
75
            'MyVarchar' => 'brng:hoE5xdUMwdJRjXi4jsGs8d_FzBzibUqmiRdoC-oo7_JsFPtz55FzAIb_Qcl-SreatW0uZViRGUvhLGbszKuIUejswmXIqYtSglkc9nHk5g==',
76
            'MyIndexedVarcharValue' => 'brng:_RZQDZXqeISYm3WtfTSAS2p0hZz-QDHAWmFSKvcaWLQ5ODRyUKKcPvsGOiIvfBPYmOJH35zh1Hrm2K2LY4ElLNVfAQN_QgcXpxWWNWI=',
77
            'MyNumberValue' => 'brng:4AB4YlC-AZHrb6d-t6aiDjZDVdg0BHRN2jAb5CoxiFN89XssvReGkbQMp9jGbXtstk1W94745WWJeiI4n05HsDPu',
78
        ];
79
        $update = new SQLUpdate("EncryptedModel", $data, "ID IN (2)");
80
        $update->execute();
81
    }
82
83
    public function tearDown()
84
    {
85
        parent::tearDown();
86
    }
87
88
    /**
89
     * @return Test_EncryptedModel
90
     */
91
    public function getTestModel()
92
    {
93
        return $this->objFromFixture(Test_EncryptedModel::class, 'demo');
94
    }
95
96
    /**
97
     * @return Test_EncryptedModel
98
     */
99
    public function getTestModel2()
100
    {
101
        return $this->objFromFixture(Test_EncryptedModel::class, 'demo2');
102
    }
103
104
    /**
105
     * @return Test_EncryptedModel
106
     */
107
    public function getTestModel3()
108
    {
109
        return $this->objFromFixture(Test_EncryptedModel::class, 'demo3');
110
    }
111
112
    /**
113
     * @return Member
114
     */
115
    public function getAdminMember()
116
    {
117
        return $this->objFromFixture(Member::class, 'admin');
118
    }
119
120
    /**
121
     * @return File
122
     */
123
    public function getRegularFile()
124
    {
125
        return $this->objFromFixture(File::class, 'regular');
126
    }
127
128
    /**
129
     * @return File
130
     */
131
    public function getEncryptedFile()
132
    {
133
        return $this->objFromFixture(File::class, 'encrypted');
134
    }
135
136
    /**
137
     * @param string $class
138
     * @param int $id
139
     * @return array
140
     */
141
    protected function fetchRawData($class, $id)
142
    {
143
        $tableName = DataObject::getSchema()->tableName($class);
144
        $columnIdentifier = DataObject::getSchema()->sqlColumnForField($class, 'ID');
145
        $sql = new SQLSelect('*', [$tableName], [$columnIdentifier => $id]);
146
        $dbRecord = $sql->firstRow()->execute()->first();
147
        return $dbRecord;
148
    }
149
150
    public function testEncryption()
151
    {
152
        $someText = 'some text';
153
        $encrypt = EncryptHelper::encrypt($someText);
154
        $decryptedValue = EncryptHelper::decrypt($encrypt);
155
156
        $this->assertEquals($someText, $decryptedValue);
157
    }
158
159
    public function testIndexes()
160
    {
161
        $indexes = DataObject::getSchema()->databaseIndexes(Test_EncryptedModel::class);
162
        $keys = array_keys($indexes);
163
        $this->assertContains('MyIndexedVarcharBlindIndex', $keys, "Index is not defined in : " . implode(", ", $keys));
164
        $this->assertContains('MyNumberLastFourBlindIndex', $keys, "Index is not defined in : " . implode(", ", $keys));
165
    }
166
167
    public function testSearch()
168
    {
169
        $singl = singleton(Test_EncryptedModel::class);
170
171
        /** @var EncryptedDBField $obj  */
172
        $obj = $singl->dbObject('MyIndexedVarchar');
173
        $record = $obj->fetchRecord('some_searchable_value');
174
175
        // echo '<pre>';print_r("From test: " . $record->MyIndexedVarchar);die();
176
        $this->assertNotEmpty($record);
177
        $this->assertEquals("some text text", $record->MyText);
178
        $this->assertEquals("some_searchable_value", $record->MyIndexedVarchar);
179
        $this->assertEquals("some_searchable_value", $record->dbObject('MyIndexedVarchar')->getValue());
180
181
        // Also search our super getter method
182
        $recordAlt = Test_EncryptedModel::getByBlindIndex('MyIndexedVarchar', 'some_searchable_value');
183
        $this->assertNotEmpty($record);
184
        $this->assertEquals($recordAlt->ID, $record->ID);
185
186
        // Can we get a list ?
187
        $list = Test_EncryptedModel::getAllByBlindIndex('MyIndexedVarchar', 'some_searchable_value');
188
        $this->assertInstanceOf(DataList::class, $list);
189
190
        $record = $obj->fetchRecord('some_unset_value');
191
        $this->assertEmpty($record);
192
193
        // Let's try our four digits index
194
        $obj = $singl->dbObject('MyNumber');
195
        $record = $obj->fetchRecord('6789', 'LastFourBlindIndex');
196
        $searchValue = $obj->getSearchValue('6789', 'LastFourBlindIndex');
197
        // $searchParams = $obj->getSearchParams('6789', 'LastFourBlindIndex');
198
        // print_r($searchParams);
199
        $this->assertNotEmpty($record, "Nothing found for $searchValue");
200
        $this->assertEquals("0123456789", $record->MyNumber);
201
    }
202
203
    public function testSearchFilter()
204
    {
205
        $record = Test_EncryptedModel::get()->filter('MyIndexedVarchar:Encrypted', 'some_searchable_value')->first();
206
        $this->assertNotEmpty($record);
207
        $this->assertEquals(1, $record->ID);
208
        $this->assertNotEquals(2, $record->ID);
209
210
        $record = Test_EncryptedModel::get()->filter('MyIndexedVarchar:Encrypted', 'some_unset_value')->first();
211
        $this->assertEmpty($record);
212
    }
213
214
    public function testRotation()
215
    {
216
        $model = $this->getTestModel3();
217
        $data = $this->fetchRawData(Test_EncryptedModel::class, $model->ID);
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
218
219
        $old = EncryptHelper::getEngineForEncryption("nacl");
220
        $result = $model->needsToRotateEncryption($old);
221
        $this->assertTrue($result);
222
223
        $result = $model->rotateEncryption($old);
224
        $this->assertTrue($result);
225
    }
226
227
    public function testCompositeOptions()
228
    {
229
        $model = $this->getTestModel();
230
231
        /** @var EncryptedDBField $myNumber */
232
        $myNumber = $model->dbObject('MyNumber');
0 ignored issues
show
Unused Code introduced by
The call to LeKoala\Encrypt\Test\Tes...ryptedModel::dbObject() has too many arguments starting with 'MyNumber'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

232
        /** @scrutinizer ignore-call */ 
233
        $myNumber = $model->dbObject('MyNumber');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
233
234
        $this->assertEquals(10, $myNumber->getDomainSize());
235
        $this->assertEquals(4, $myNumber->getOutputSize());
236
        $this->assertEquals(EncryptedDBField::LARGE_INDEX_SIZE, $myNumber->getIndexSize());
237
238
        /** @var EncryptedDBField $MyIndexedVarchar */
239
        $MyIndexedVarchar = $model->dbObject('MyIndexedVarchar');
240
241
        // Default config values
242
        $this->assertEquals(EncryptHelper::DEFAULT_DOMAIN_SIZE, $MyIndexedVarchar->getDomainSize());
243
        $this->assertEquals(EncryptHelper::DEFAULT_OUTPUT_SIZE, $MyIndexedVarchar->getOutputSize());
244
        $this->assertEquals(EncryptedDBField::LARGE_INDEX_SIZE, $MyIndexedVarchar->getIndexSize());
245
    }
246
247
    public function testIndexPlanner()
248
    {
249
        $sizes = EncryptHelper::planIndexSizesForClass(Test_EncryptedModel::class);
250
        $this->assertNotEmpty($sizes);
251
        $this->assertArrayHasKey("min", $sizes);
252
        $this->assertArrayHasKey("max", $sizes);
253
        $this->assertArrayHasKey("indexes", $sizes);
254
        $this->assertArrayHasKey("estimated_population", $sizes);
255
        $this->assertArrayHasKey("coincidence_count", $sizes);
256
    }
257
258
    public function testFixture()
259
    {
260
        // this one use nacl encryption and will be rotated transparently
261
        $model = $this->getTestModel();
262
263
        $result = $model->needsToRotateEncryption(EncryptHelper::getEngineForEncryption("nacl"));
264
        $this->assertTrue($result);
265
266
        // Ensure we have our blind indexes
267
        $this->assertTrue($model->hasDatabaseField('MyIndexedVarcharValue'));
268
        $this->assertTrue($model->hasDatabaseField('MyIndexedVarcharBlindIndex'));
269
        $this->assertTrue($model->hasDatabaseField('MyNumberValue'));
270
        $this->assertTrue($model->hasDatabaseField('MyNumberBlindIndex'));
271
        $this->assertTrue($model->hasDatabaseField('MyNumberLastFourBlindIndex'));
272
273
        if (class_uses($model, HasEncryptedFields::class)) {
0 ignored issues
show
Bug introduced by
LeKoala\Encrypt\HasEncryptedFields::class of type string is incompatible with the type boolean expected by parameter $autoload of class_uses(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

273
        if (class_uses($model, /** @scrutinizer ignore-type */ HasEncryptedFields::class)) {
Loading history...
274
            $this->assertTrue($model->hasEncryptedField('MyVarchar'));
275
            $this->assertTrue($model->hasEncryptedField('MyIndexedVarchar'));
276
        }
277
278
        // print_r($model);
279
        /*
280
         [record:protected] => Array
281
        (
282
            [ClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
283
            [LastEdited] => 2020-12-15 10:09:47
284
            [Created] => 2020-12-15 10:09:47
285
            [Name] => demo
286
            [MyText] => nacl:mQ1g5ugjYSWjFd-erM6-xlB_EbWp1bOAUPbL4fa3Ce5SX6LP7sFCczkFx_lRABvZioWJXx-L
287
            [MyHTMLText] => nacl:836In6YCaEf3_mRJR7NOC_s0P8gIFESgmPnHCefTe6ycY_6CLKVmT0_9KWHgnin-WGXMJawkS1hS87xwQw==
288
            [MyVarchar] => nacl:ZeOw8-dcBdFemtGm-MRJ5pCSipOtAO5-zBRms8F5Elex08GuoL_JKbdN-CiOP-u009MJfvGZUkx9Ru5Zn0_y
289
            [RegularFileID] => 2
290
            [EncryptedFileID] => 3
291
            [MyIndexedVarcharBlindIndex] => 04bb6edd
292
            [ID] => 1
293
            [RecordClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
294
        )
295
        */
296
297
        $varcharValue = 'encrypted varchar value';
298
        $varcharWithIndexValue = 'some_searchable_value';
299
        // regular fields are not affected
300
        $this->assertEquals('demo', $model->Name);
301
302
        // get value
303
        $this->assertEquals($varcharValue, $model->dbObject('MyVarchar')->getValue());
0 ignored issues
show
Unused Code introduced by
The call to LeKoala\Encrypt\Test\Tes...ryptedModel::dbObject() has too many arguments starting with 'MyVarchar'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

303
        $this->assertEquals($varcharValue, $model->/** @scrutinizer ignore-call */ dbObject('MyVarchar')->getValue());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
304
        // encrypted fields work transparently when using trait
305
        $this->assertEquals($varcharValue, $model->MyVarchar);
306
307
308
        $this->assertTrue($model->dbObject('MyIndexedVarchar') instanceof EncryptedDBField);
309
        $this->assertTrue($model->dbObject('MyIndexedVarchar')->hasField('Value'));
310
311
        $model->MyIndexedVarchar = $varcharWithIndexValue;
0 ignored issues
show
Bug Best Practice introduced by
The property MyIndexedVarchar does not exist on LeKoala\Encrypt\Test\Test_EncryptedModel. Since you implemented __set, consider adding a @property annotation.
Loading history...
312
        $model->write();
313
        $this->assertEquals($varcharWithIndexValue, $model->MyIndexedVarchar);
0 ignored issues
show
Bug Best Practice introduced by
The property MyIndexedVarchar does not exist on LeKoala\Encrypt\Test\Test_EncryptedModel. Since you implemented __get, consider adding a @property annotation.
Loading history...
314
315
        $dbRecord = $this->fetchRawData(get_class($model), $model->ID);
316
        // print_r($dbRecord);
317
        /*
318
        Array
319
(
320
    [ID] => 1
321
    [ClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
322
    [LastEdited] => 2020-12-15 10:10:27
323
    [Created] => 2020-12-15 10:10:27
324
    [Name] => demo
325
    [MyText] => nacl:aDplmA9hs7naqiPwWdNRMcYNUltf4mOs8KslRQZ4vCdnJylnbjAJYChtVH7wiiygsAHWqbM6
326
    [MyHTMLText] => nacl:dMvk5Miux0bsSP1SjaXQRlbGogNTu7UD3p6AlNHFMAEGXOQz03hkBx43C-WelCS0KUdAN9ewuwuXZqMmRA==
327
    [MyVarchar] => nacl:sZRenCG6En7Sg_HmsUHkNy_1MXOstly7eHm0i2iq83kTFH40UsQj-HTqxxYfx0ghuWSKbcqHQ7_OAEy4pcPm
328
    [RegularFileID] => 2
329
    [EncryptedFileID] => 3
330
    [MyNumberValue] =>
331
    [MyNumberBlindIndex] =>
332
    [MyNumberLastFourBlindIndex] =>
333
    [MyIndexedVarcharValue] =>
334
    [MyIndexedVarcharBlindIndex] => 04bb6edd
335
)
336
*/
337
        $this->assertNotEquals($varcharValue, $dbRecord['MyVarchar']);
338
        $this->assertNotEmpty($dbRecord['MyVarchar']);
339
        $this->assertTrue(EncryptHelper::isEncrypted($dbRecord['MyVarchar']));
340
    }
341
342
    public function testFixture2()
343
    {
344
        // this one has only brng encryption
345
        $model = $this->getTestModel2();
346
347
        $result = $model->needsToRotateEncryption(EncryptHelper::getCipherSweet());
348
        $this->assertFalse($result);
349
350
        // Ensure we have our blind indexes
351
        $this->assertTrue($model->hasDatabaseField('MyIndexedVarcharValue'));
352
        $this->assertTrue($model->hasDatabaseField('MyIndexedVarcharBlindIndex'));
353
        $this->assertTrue($model->hasDatabaseField('MyNumberValue'));
354
        $this->assertTrue($model->hasDatabaseField('MyNumberBlindIndex'));
355
        $this->assertTrue($model->hasDatabaseField('MyNumberLastFourBlindIndex'));
356
357
        if (class_uses($model, HasEncryptedFields::class)) {
0 ignored issues
show
Bug introduced by
LeKoala\Encrypt\HasEncryptedFields::class of type string is incompatible with the type boolean expected by parameter $autoload of class_uses(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

357
        if (class_uses($model, /** @scrutinizer ignore-type */ HasEncryptedFields::class)) {
Loading history...
358
            $this->assertTrue($model->hasEncryptedField('MyVarchar'));
359
            $this->assertTrue($model->hasEncryptedField('MyIndexedVarchar'));
360
        }
361
362
363
        // print_r($model);
364
        /*
365
        [record:protected] => Array
366
        (
367
            [ClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
368
            [LastEdited] => 2021-07-07 13:38:48
369
            [Created] => 2021-07-07 13:38:48
370
            [Name] => demo2
371
            [MyText] => brng:XLzehy47IgENco4DcZj75u9D2p53UjDMCmTFGPNdmzYYxVVbDsaVWuZP1dTvIDaYagVggNAxT8S9fUTXw55VyIv6OxYJrQ==
372
            [MyHTMLText] => brng:bJ-6iGa-gjl9M6-UaNvtSrRuFLwDTLC6SIekrPHTcN_nmIUaK_VEFNAGVd3q__siNsvVXLreSlunpSyJ4JmF8eyI12ltz_s-eV6WVXw=
373
            [MyVarchar] => brng:qNEVUW3TS6eACSS4v1_NK0FOiG5JnbihmOHR1DU4L8Pt63OXQIJr_Kpd34J1IHaJXZWt4uuk2SZgskmvf8FrfApag_sRypca87MegXg_wQ==
374
            [RegularFileID] => 0
375
            [EncryptedFileID] => 0
376
            [MyNumberValue] => brng:pKYd8mXDduwhudwWeoE_ByO6IkvVlykVa6h09DTYFdHcb52yA1R5yhTEqQQjz1ndADFRa9WLLM3_e1U8PfPTiP4E
377
            [MyNumberBlindIndex] => a1de44f9
378
            [MyNumberLastFourBlindIndex] => addb
379
            [MyIndexedVarcharValue] => brng:TBD63tu-P9PluzI_zKTZ17P-4bhFvhbW7eOeSOOnDEf7n3Ytv2_52rlvGTVSJeWr5f6Z5eqrxi-RL5B6V0PrUmEqhfE2TGt-IdH5hfU=
380
            [MyIndexedVarcharBlindIndex] => 216d113a
381
            [ID] => 2
382
            [RecordClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
383
        )
384
        */
385
386
        $varcharValue = 'encrypted varchar value';
387
        $varcharWithIndexValue = 'some_searchable_value';
388
        // regular fields are not affected
389
        $this->assertEquals('demo2', $model->Name);
390
391
        // get value
392
        $this->assertEquals($varcharValue, $model->dbObject('MyVarchar')->getValue());
0 ignored issues
show
Unused Code introduced by
The call to LeKoala\Encrypt\Test\Tes...ryptedModel::dbObject() has too many arguments starting with 'MyVarchar'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

392
        $this->assertEquals($varcharValue, $model->/** @scrutinizer ignore-call */ dbObject('MyVarchar')->getValue());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
393
        // encrypted fields work transparently when using trait
394
        $this->assertEquals($varcharValue, $model->MyVarchar);
395
396
397
        $this->assertTrue($model->dbObject('MyIndexedVarchar') instanceof EncryptedDBField);
398
        $this->assertTrue($model->dbObject('MyIndexedVarchar')->hasField('Value'));
399
400
        $model->MyIndexedVarchar = $varcharWithIndexValue;
0 ignored issues
show
Bug Best Practice introduced by
The property MyIndexedVarchar does not exist on LeKoala\Encrypt\Test\Test_EncryptedModel. Since you implemented __set, consider adding a @property annotation.
Loading history...
401
        $model->write();
402
        $this->assertEquals($varcharWithIndexValue, $model->MyIndexedVarchar);
0 ignored issues
show
Bug Best Practice introduced by
The property MyIndexedVarchar does not exist on LeKoala\Encrypt\Test\Test_EncryptedModel. Since you implemented __get, consider adding a @property annotation.
Loading history...
403
404
        $dbRecord = $this->fetchRawData(get_class($model), $model->ID);
405
        // print_r($dbRecord);
406
        /*
407
        Array
408
(
409
    [ID] => 2
410
    [ClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
411
    [LastEdited] => 2021-07-07 13:52:10
412
    [Created] => 2021-07-07 13:52:08
413
    [Name] => demo2
414
    [MyText] => brng:IQ-6VoXJedlAGdoCPFUVTSnipUPR4k9YSi3Ik8_oPfUmMVDhA1kgTBFdG_6k08xLhD39G0ksVD_nMtUF4Opo6Zxgkc5Qww==
415
    [MyHTMLText] => brng:ATmS8Tooc0j2FN5zB8ojmhgNHD-vncvm1ljX8aF7rR6bbsD8pEwyX7BJ3mPg6WEzwyye4uriGskFy30GL9LEKsGs1hs40JJgs6rgwKA=
416
    [MyVarchar] => brng:zxu2RFNjqDGV0JmxF1WPMtxDKTyfOtvVztXfbnV3aYJAzro7RwHhSs8HhasHvdPOQ2Vxi_oDieRgcE8XeP3nyoF3tYJrJp3Mo9XdYXj2tw==
417
    [RegularFileID] => 0
418
    [EncryptedFileID] => 0
419
    [MyNumberValue] => brng:pKYd8mXDduwhudwWeoE_ByO6IkvVlykVa6h09DTYFdHcb52yA1R5yhTEqQQjz1ndADFRa9WLLM3_e1U8PfPTiP4E
420
    [MyNumberBlindIndex] => a1de44f9
421
    [MyNumberLastFourBlindIndex] => addb
422
    [MyIndexedVarcharValue] => brng:0ow_r7UD3FXYXxq7kjVzA3uY1ThFYfAWxZFAHA0aRoohLfQW_ZBa0Q8w5A3hyLJhT6djM6xR43O_jeEfP-w_fRaH3nXRI5RW7tO78JY=
423
    [MyIndexedVarcharBlindIndex] => 216d113a
424
)
425
*/
426
        $this->assertNotEquals($varcharValue, $dbRecord['MyVarchar']);
427
        $this->assertNotEmpty($dbRecord['MyVarchar']);
428
        $this->assertTrue(EncryptHelper::isEncrypted($dbRecord['MyVarchar']));
429
    }
430
431
    public function testRecordIsEncrypted()
432
    {
433
        $model = new Test_EncryptedModel();
434
435
        // echo "*** start \n";
436
        // Let's write some stuff
437
        $someText = 'some text';
438
        $model->MyText = $someText . ' text';
439
        $model->MyHTMLText = '<p>' . $someText . ' html</p>';
440
        $model->MyVarchar = 'encrypted varchar value';
441
        $model->MyIndexedVarchar = "some_searchable_value";
0 ignored issues
show
Bug Best Practice introduced by
The property MyIndexedVarchar does not exist on LeKoala\Encrypt\Test\Test_EncryptedModel. Since you implemented __set, consider adding a @property annotation.
Loading history...
442
        $model->MyNumber = "0123456789";
443
        // All fields are marked as changed, including "hidden" fields
444
        // MyNumber will mark as changed MyNumber, MyNumberValue, MuNumberBlindIndex, MyNumberLastFourBlindIndex
445
        // echo '<pre>';
446
        // print_r(array_keys($model->getChangedFields()));
447
        // die();
448
        $id = $model->write();
449
450
        $this->assertNotEmpty($id);
451
452
        // For the model, its the same
453
        $this->assertEquals($someText . ' text', $model->MyText);
454
        $this->assertEquals($someText . ' text', $model->dbObject('MyText')->getValue());
0 ignored issues
show
Unused Code introduced by
The call to LeKoala\Encrypt\Test\Tes...ryptedModel::dbObject() has too many arguments starting with 'MyText'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

454
        $this->assertEquals($someText . ' text', $model->/** @scrutinizer ignore-call */ dbObject('MyText')->getValue());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
455
        $this->assertEquals($someText . ' text', $model->getField('MyText'));
456
        $this->assertEquals('<p>' . $someText . ' html</p>', $model->MyHTMLText);
457
458
        // In the db, it's not the same
459
        $dbRecord = $this->fetchRawData(get_class($model), $model->ID);
460
461
        if (!EncryptHelper::isEncrypted($dbRecord['MyIndexedVarcharValue'])) {
462
            print_r($dbRecord);
463
        }
464
465
        /*
466
(
467
    [ID] => 2
468
    [ClassName] => LeKoala\Encrypt\Test\Test_EncryptedModel
469
    [LastEdited] => 2020-12-15 10:20:39
470
    [Created] => 2020-12-15 10:20:39
471
    [Name] =>
472
    [MyText] => nacl:yA3XhjUpxE6cS3VMOVI4eqpolP1vRZDYjFySULZiazi9V3HSugC3t8KgImnGV5jP1VzEytVX
473
    [MyHTMLText] => nacl:F3D33dZ2O7qtlmkX-fiaYwSjAo6RC03aiAWRTkfSJOZikcSfezjwmi9DPJ4EO0hYeVc9faRgA3RmTDajRA==
474
    [MyVarchar] => nacl:POmdt3mTUSgPJw3ttfi2G9HgHAE4FRX4FQ5CSBicj4JsEwyPwrP-JKYGcs5drFYLId3cMVf6m8daUY7Ao4Cz
475
    [RegularFileID] => 0
476
    [EncryptedFileID] => 0
477
    [MyNumberValue] => nacl:2wFOX_qahm-HmzQPXvcBFhWCG1TaGQgeM7vkebLxRXDfMpzAxhxkExVgBi8caPYrwvA=
478
    [MyNumberBlindIndex] => 5e0bd888
479
    [MyNumberLastFourBlindIndex] => 276b
480
    [MyIndexedVarcharValue] => nacl:BLi-zF02t0Zet-ADP3RT8v5RTsM11WKIyjlJ1EVHIai2HwjxCIq92gfsay5zqiLic14dXtwigb1kI179QQ==
481
    [MyIndexedVarcharBlindIndex] => 04bb6edd
482
)
483
        */
484
        $text = isset($dbRecord['MyText']) ? $dbRecord['MyText'] : null;
485
        $this->assertNotEmpty($text);
486
        $this->assertNotEquals($someText, $text, "Data is not encrypted in the database");
487
        // Composite fields should work as well
488
        $this->assertNotEmpty($dbRecord['MyIndexedVarcharValue']);
489
        $this->assertNotEmpty($dbRecord['MyIndexedVarcharBlindIndex']);
490
491
        // Test save into
492
        $modelFieldsBefore = $model->getQueriedDatabaseFields();
493
        $model->MyIndexedVarchar = 'new_value';
494
        $dbObj = $model->dbObject('MyIndexedVarchar');
495
        // $dbObj->setValue('new_value', $model);
496
        // $dbObj->saveInto($model);
497
        $modelFields = $model->getQueriedDatabaseFields();
498
        // print_r($modelFields);
499
        $this->assertTrue($dbObj->isChanged());
500
        $changed = implode(", ", array_keys($model->getChangedFields()));
501
        $this->assertNotEquals($modelFieldsBefore['MyIndexedVarchar'], $modelFields['MyIndexedVarchar'], "It should not have the same value internally anymore");
502
        $this->assertTrue($model->isChanged('MyIndexedVarchar'), "Field is not properly marked as changed, only have : " . $changed);
503
        $this->assertEquals('new_value', $dbObj->getValue());
504
        $this->assertNotEquals('new_value', $modelFields['MyIndexedVarcharValue'], "Unencrypted value is not set on value field");
505
506
        // Somehow this is not working on travis? composite fields don't save encrypted data although it works locally
507
        $this->assertNotEquals("some_searchable_value", $dbRecord['MyIndexedVarcharValue'], "Data is not encrypted in the database");
508
509
        // if we load again ?
510
        // it should work thanks to our trait
511
        // by default, data will be loaded encrypted if we don't use the trait and call getField directly
512
        $model2 = $model::get()->byID($model->ID);
513
        $this->assertEquals($someText . ' text', $model2->MyText, "Data does not load properly");
514
        $this->assertEquals('<p>' . $someText . ' html</p>', $model2->MyHTMLText, "Data does not load properly");
515
    }
516
517
    public function testFileEncryption()
518
    {
519
        $regularFile = $this->getRegularFile();
520
        $encryptedFile = $this->getEncryptedFile();
521
522
        $this->assertEquals(0, $regularFile->Encrypted);
523
        $this->assertEquals(1, $encryptedFile->Encrypted);
524
525
        // test encryption
526
527
        $string = 'Some content';
528
529
        $stream = fopen('php://memory', 'r+');
530
        fwrite($stream, $string);
531
        rewind($stream);
532
533
        $encryptedFile->setFromStream($stream, 'secret.doc');
534
        $encryptedFile->write();
535
536
        $this->assertFalse($encryptedFile->isEncrypted());
537
538
        $encryptedFile->encryptFileIfNeeded();
539
540
        $this->assertTrue($encryptedFile->isEncrypted());
541
    }
542
}
543