Skip to content

Commit

Permalink
Fixes AsEncryptedObject traits not respecting nullable columns.
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkGhostHunter committed Nov 30, 2021
1 parent a8f9d65 commit aff3151
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 5 deletions.
14 changes: 11 additions & 3 deletions src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php
Expand Up @@ -20,17 +20,25 @@ public static function castUsing(array $arguments)
{
public function get($model, $key, $value, $attributes)
{
return new ArrayObject(json_decode(Crypt::decryptString($attributes[$key]), true));
if (isset($attributes[$key])) {
return new ArrayObject(json_decode(Crypt::decryptString($attributes[$key]), true));
}

return null;
}

public function set($model, $key, $value, $attributes)
{
return [$key => Crypt::encryptString(json_encode($value))];
if ($value !== null) {
return [$key => Crypt::encryptString(json_encode($value))];
}

return null;
}

public function serialize($model, string $key, $value, array $attributes)
{
return $value->getArrayCopy();
return $value !== null ? $value->getArrayCopy() : null;
}
};
}
Expand Down
12 changes: 10 additions & 2 deletions src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php
Expand Up @@ -21,12 +21,20 @@ public static function castUsing(array $arguments)
{
public function get($model, $key, $value, $attributes)
{
return new Collection(json_decode(Crypt::decryptString($attributes[$key]), true));
if (isset($attributes[$key])) {
return new Collection(json_decode(Crypt::decryptString($attributes[$key]), true));
}

return null;
}

public function set($model, $key, $value, $attributes)
{
return [$key => Crypt::encryptString(json_encode($value))];
if ($value !== null) {
return [$key => Crypt::encryptString(json_encode($value))];
}

return null;
}
};
}
Expand Down
107 changes: 107 additions & 0 deletions tests/Integration/Database/EloquentModelEncryptedCastingTest.php
Expand Up @@ -3,6 +3,9 @@
namespace Illuminate\Tests\Integration\Database;

use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Database\Eloquent\Casts\ArrayObject;
use Illuminate\Database\Eloquent\Casts\AsEncryptedArrayObject;
use Illuminate\Database\Eloquent\Casts\AsEncryptedCollection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Collection;
Expand Down Expand Up @@ -178,6 +181,110 @@ public function testCollectionIsCastable()
]);
}

public function testAsEncryptedCollection()
{
$this->encrypter->expects('encryptString')
->twice()
->with('{"key1":"value1"}')
->andReturn('encrypted-secret-collection-string-1');
$this->encrypter->expects('encryptString')
->times(12)
->with('{"key1":"value1","key2":"value2"}')
->andReturn('encrypted-secret-collection-string-2');
$this->encrypter->expects('decryptString')
->once()
->with('encrypted-secret-collection-string-2')
->andReturn('{"key1":"value1","key2":"value2"}');

$subject = new EncryptedCast;

$subject->mergeCasts(['secret_collection' => AsEncryptedCollection::class]);

$subject->secret_collection = new Collection(['key1' => 'value1']);
$subject->secret_collection->put('key2', 'value2');

$subject->save();

$this->assertInstanceOf(Collection::class, $subject->secret_collection);
$this->assertSame('value1', $subject->secret_collection->get('key1'));
$this->assertSame('value2', $subject->secret_collection->get('key2'));
$this->assertDatabaseHas('encrypted_casts', [
'id' => $subject->id,
'secret_collection' => 'encrypted-secret-collection-string-2',
]);

$subject = $subject->fresh();

$this->assertInstanceOf(Collection::class, $subject->secret_collection);
$this->assertSame('value1', $subject->secret_collection->get('key1'));
$this->assertSame('value2', $subject->secret_collection->get('key2'));

$subject->secret_collection = null;
$subject->save();

$this->assertNull($subject->secret_collection);
$this->assertDatabaseHas('encrypted_casts', [
'id' => $subject->id,
'secret_collection' => null,
]);

$this->assertNull($subject->fresh()->secret_collection);
}

public function testAsEncryptedArrayObject()
{
$this->encrypter->expects('encryptString')
->once()
->with('{"key1":"value1"}')
->andReturn('encrypted-secret-array-string-1');
$this->encrypter->expects('decryptString')
->once()
->with('encrypted-secret-array-string-1')
->andReturn('{"key1":"value1"}');
$this->encrypter->expects('encryptString')
->times(12)
->with('{"key1":"value1","key2":"value2"}')
->andReturn('encrypted-secret-array-string-2');
$this->encrypter->expects('decryptString')
->once()
->with('encrypted-secret-array-string-2')
->andReturn('{"key1":"value1","key2":"value2"}');

$subject = new EncryptedCast;

$subject->mergeCasts(['secret_array' => AsEncryptedArrayObject::class]);

$subject->secret_array = ['key1' => 'value1'];
$subject->secret_array['key2'] = 'value2';

$subject->save();

$this->assertInstanceOf(ArrayObject::class, $subject->secret_array);
$this->assertSame('value1', $subject->secret_array['key1']);
$this->assertSame('value2', $subject->secret_array['key2']);
$this->assertDatabaseHas('encrypted_casts', [
'id' => $subject->id,
'secret_array' => 'encrypted-secret-array-string-2',
]);

$subject = $subject->fresh();

$this->assertInstanceOf(ArrayObject::class, $subject->secret_array);
$this->assertSame('value1', $subject->secret_array['key1']);
$this->assertSame('value2', $subject->secret_array['key2']);

$subject->secret_array = null;
$subject->save();

$this->assertNull($subject->secret_array);
$this->assertDatabaseHas('encrypted_casts', [
'id' => $subject->id,
'secret_array' => null,
]);

$this->assertNull($subject->fresh()->secret_array);
}

public function testCustomEncrypterCanBeSpecified()
{
$customEncrypter = $this->mock(Encrypter::class);
Expand Down

0 comments on commit aff3151

Please sign in to comment.