Merge pull request #5 from bjornvoesten/development

Added nullable attributes
This commit is contained in:
Bjorn Voesten 2021-01-22 00:23:16 +01:00 committed by GitHub
commit 5fdadf1b46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 53 deletions

View File

@ -13,10 +13,10 @@ class Encrypted implements CastsAttributes
* @param string $key
* @param mixed $value
* @param array $attributes
* @return string
* @return string|null
* @throws \Exception
*/
public function get($model, string $key, $value, array $attributes)
public function get($model, string $key, $value, array $attributes): ?string
{
return $model->decrypt($key);
}

View File

@ -108,23 +108,23 @@ class CipherSweetService
$field = new EncryptedField(
$this->engine,
$table = $model->getTable(),
$attribute->column,
$attribute->column
);
// Map and add the indexes to the encrypted
// field instance.
collect($attribute->indexes)
->map(function (Index $index) {
return $index = new BlindIndex(
->map(static function (Index $index) {
return new BlindIndex(
$index->column,
$index->transformers,
$index->bits,
$index->fast,
$index->fast
);
})
->each(
fn($index) => $field->addBlindIndex($index)
);
->each(static function ($index) use ($field) {
return $field->addBlindIndex($index);
});
return $field;
}
@ -134,18 +134,24 @@ class CipherSweetService
*
* @param \Illuminate\Database\Eloquent\Model|\BjornVoesten\CipherSweet\Concerns\WithAttributeEncryption $model
* @param string $attribute
* @param string|int|boolean $value
* @param string|int|boolean|null $value
* @return array
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNameCollisionException
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNotFoundException
* @throws \ParagonIE\CipherSweet\Exception\CryptoOperationException
* @throws \SodiumException
*/
public function encrypt(Model $model, string $attribute, $value)
public function encrypt(Model $model, string $attribute, $value): array
{
return $this
->field($model, $attribute)
->prepareForStorage($value);
$field = $this->field($model, $attribute);
if (is_null($value)) {
return [null, array_map(static function () {
return null;
}, $field->getAllBlindIndexes(''))];
}
return $field->prepareForStorage($value);
}
/**
@ -158,8 +164,12 @@ class CipherSweetService
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNameCollisionException
* @throws \ParagonIE\CipherSweet\Exception\CryptoOperationException
*/
public function decrypt(Model $model, string $attribute, $value)
public function decrypt(Model $model, string $attribute, $value): ?string
{
if (is_null($value)) {
return null;
}
return $this
->field($model, $attribute)
->decryptValue($value);

View File

@ -35,12 +35,12 @@ trait WithAttributeEncryption
* Encrypt the attribute.
*
* @param string $attribute
* @return string
* @return string|null
*/
public function decrypt(string $attribute): string
public function decrypt(string $attribute): ?string
{
return app('ciphersweet')->decrypt(
$this, $attribute, $this->attributes[$attribute]
$this, $attribute, $this->attributes[$attribute] ?? null
);
}

View File

@ -10,8 +10,8 @@ trait CreateUsersTable
protected function createUsersTable(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id('id');
$table->string('social_security_number');
$table->id();
$table->string('social_security_number')->nullable();
$table->string('social_security_number_index')->nullable();
$table->string('custom_index')->nullable();
$table->timestamps();

View File

@ -9,10 +9,10 @@ trait CreatesUsers
/**
* Create a new user instance.
*
* @param string $socialSecurityNumber
* @param string|null $socialSecurityNumber
* @return \Tests\Mocks\User|\Illuminate\Database\Eloquent\Model
*/
protected function user(string $socialSecurityNumber): User
protected function user(?string $socialSecurityNumber): User
{
return User::query()->create([
'social_security_number' => $socialSecurityNumber,

View File

@ -27,12 +27,12 @@ class EncryptionTest extends TestCase
'social_security_number' => '123-456-789',
]);
$this->assertSame(
static::assertSame(
'123-456-789',
$user->social_security_number
);
$this->assertNotEmpty(
static::assertNotEmpty(
$user->social_security_number_index
);
}
@ -41,12 +41,12 @@ class EncryptionTest extends TestCase
{
$user = $this->user('123-456-789');
$this->assertNotSame(
static::assertNotSame(
'123-456-789',
$user->getRawOriginal('social_security_number')
);
$this->assertNotEmpty(
static::assertNotEmpty(
$user->social_security_number_index
);
@ -78,12 +78,12 @@ class EncryptionTest extends TestCase
])
->save();
$this->assertNotSame(
static::assertNotSame(
'123-456-789',
$user->getRawOriginal('social_security_number')
);
$this->assertNotEmpty(
static::assertNotEmpty(
$user->getAttribute('custom_index')
);
@ -100,9 +100,29 @@ class EncryptionTest extends TestCase
{
$user = $this->user('123-456-789');
$this->assertSame(
static::assertSame(
'123-456-789',
$user->getAttribute('social_security_number')
);
}
public function testAttributesCanBeMadeNull(): void
{
$user = $this->user('123-456-789');
static::assertSame(
'123-456-789',
$user->social_security_number
);
$user->social_security_number = null;
static::assertNull(
$user->social_security_number
);
static::assertNull(
$user->social_security_number_index
);
}
}

View File

@ -32,8 +32,8 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertNotContains($userTwo->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertNotContains($userTwo->id, $keys);
// Assert success using provided index.
/** @var \Illuminate\Database\Eloquent\Collection $keys */
@ -44,8 +44,8 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertNotContains($userTwo->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertNotContains($userTwo->id, $keys);
// Assert undefined index exception.
$this->expectException(Exception::class);
@ -57,6 +57,22 @@ class QueryTest extends TestCase
->get();
}
public function testCanQueryNullableAttributes(): void
{
$userOne = $this->user('123-456-789');
$userTwo = $this->user(null);
// Assert success.
/** @var \Illuminate\Database\Eloquent\Collection $keys */
$keys = User::query()
->whereEncrypted('social_security_number', '=', '123-456-789')
->get()
->modelKeys();
static::assertContains($userOne->id, $keys);
static::assertNotContains($userTwo->id, $keys);
}
public function testCanQueryEncryptedAttributeWithOrWhereClause(): void
{
$userOne = $this->user('123-456-789');
@ -71,9 +87,9 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertNotContains($userTwo->id, $keys);
$this->assertContains($userThree->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertNotContains($userTwo->id, $keys);
static::assertContains($userThree->id, $keys);
// Assert success using provided index.
/** @var \Illuminate\Database\Eloquent\Collection $keys */
@ -85,9 +101,9 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertNotContains($userTwo->id, $keys);
$this->assertContains($userThree->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertNotContains($userTwo->id, $keys);
static::assertContains($userThree->id, $keys);
// Assert undefined index exception.
$this->expectException(Exception::class);
@ -118,9 +134,9 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertContains($userTwo->id, $keys);
$this->assertNotContains($userThree->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertContains($userTwo->id, $keys);
static::assertNotContains($userThree->id, $keys);
// Assert success using provided index.
/** @var \Illuminate\Database\Eloquent\Collection $keys */
@ -136,9 +152,9 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertContains($userTwo->id, $keys);
$this->assertNotContains($userThree->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertContains($userTwo->id, $keys);
static::assertNotContains($userThree->id, $keys);
$keys = User::query()
->whereInEncrypted(
@ -149,7 +165,7 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertEmpty($keys);
static::assertEmpty($keys);
}
public function testCanQueryEncryptedAttributeWithOrWhereInClause(): void
@ -172,9 +188,9 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertContains($userTwo->id, $keys);
$this->assertNotContains($userThree->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertContains($userTwo->id, $keys);
static::assertNotContains($userThree->id, $keys);
// Assert success using provided index.
/** @var \Illuminate\Database\Eloquent\Collection $keys */
@ -192,9 +208,9 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertContains($userOne->id, $keys);
$this->assertContains($userTwo->id, $keys);
$this->assertNotContains($userThree->id, $keys);
static::assertContains($userOne->id, $keys);
static::assertContains($userTwo->id, $keys);
static::assertNotContains($userThree->id, $keys);
$keys = User::query()
->whereInEncrypted(
@ -210,6 +226,6 @@ class QueryTest extends TestCase
->get()
->modelKeys();
$this->assertEmpty($keys);
static::assertEmpty($keys);
}
}