Merge pull request #5 from bjornvoesten/development
Added nullable attributes
This commit is contained in:
commit
5fdadf1b46
|
|
@ -13,10 +13,10 @@ class Encrypted implements CastsAttributes
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param array $attributes
|
* @param array $attributes
|
||||||
* @return string
|
* @return string|null
|
||||||
* @throws \Exception
|
* @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);
|
return $model->decrypt($key);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,23 +108,23 @@ class CipherSweetService
|
||||||
$field = new EncryptedField(
|
$field = new EncryptedField(
|
||||||
$this->engine,
|
$this->engine,
|
||||||
$table = $model->getTable(),
|
$table = $model->getTable(),
|
||||||
$attribute->column,
|
$attribute->column
|
||||||
);
|
);
|
||||||
|
|
||||||
// Map and add the indexes to the encrypted
|
// Map and add the indexes to the encrypted
|
||||||
// field instance.
|
// field instance.
|
||||||
collect($attribute->indexes)
|
collect($attribute->indexes)
|
||||||
->map(function (Index $index) {
|
->map(static function (Index $index) {
|
||||||
return $index = new BlindIndex(
|
return new BlindIndex(
|
||||||
$index->column,
|
$index->column,
|
||||||
$index->transformers,
|
$index->transformers,
|
||||||
$index->bits,
|
$index->bits,
|
||||||
$index->fast,
|
$index->fast
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
->each(
|
->each(static function ($index) use ($field) {
|
||||||
fn($index) => $field->addBlindIndex($index)
|
return $field->addBlindIndex($index);
|
||||||
);
|
});
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
|
@ -134,18 +134,24 @@ class CipherSweetService
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Model|\BjornVoesten\CipherSweet\Concerns\WithAttributeEncryption $model
|
* @param \Illuminate\Database\Eloquent\Model|\BjornVoesten\CipherSweet\Concerns\WithAttributeEncryption $model
|
||||||
* @param string $attribute
|
* @param string $attribute
|
||||||
* @param string|int|boolean $value
|
* @param string|int|boolean|null $value
|
||||||
* @return array
|
* @return array
|
||||||
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNameCollisionException
|
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNameCollisionException
|
||||||
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNotFoundException
|
* @throws \ParagonIE\CipherSweet\Exception\BlindIndexNotFoundException
|
||||||
* @throws \ParagonIE\CipherSweet\Exception\CryptoOperationException
|
* @throws \ParagonIE\CipherSweet\Exception\CryptoOperationException
|
||||||
* @throws \SodiumException
|
* @throws \SodiumException
|
||||||
*/
|
*/
|
||||||
public function encrypt(Model $model, string $attribute, $value)
|
public function encrypt(Model $model, string $attribute, $value): array
|
||||||
{
|
{
|
||||||
return $this
|
$field = $this->field($model, $attribute);
|
||||||
->field($model, $attribute)
|
|
||||||
->prepareForStorage($value);
|
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\BlindIndexNameCollisionException
|
||||||
* @throws \ParagonIE\CipherSweet\Exception\CryptoOperationException
|
* @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
|
return $this
|
||||||
->field($model, $attribute)
|
->field($model, $attribute)
|
||||||
->decryptValue($value);
|
->decryptValue($value);
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,12 @@ trait WithAttributeEncryption
|
||||||
* Encrypt the attribute.
|
* Encrypt the attribute.
|
||||||
*
|
*
|
||||||
* @param string $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(
|
return app('ciphersweet')->decrypt(
|
||||||
$this, $attribute, $this->attributes[$attribute]
|
$this, $attribute, $this->attributes[$attribute] ?? null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ trait CreateUsersTable
|
||||||
protected function createUsersTable(): void
|
protected function createUsersTable(): void
|
||||||
{
|
{
|
||||||
Schema::create('users', function (Blueprint $table) {
|
Schema::create('users', function (Blueprint $table) {
|
||||||
$table->id('id');
|
$table->id();
|
||||||
$table->string('social_security_number');
|
$table->string('social_security_number')->nullable();
|
||||||
$table->string('social_security_number_index')->nullable();
|
$table->string('social_security_number_index')->nullable();
|
||||||
$table->string('custom_index')->nullable();
|
$table->string('custom_index')->nullable();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ trait CreatesUsers
|
||||||
/**
|
/**
|
||||||
* Create a new user instance.
|
* Create a new user instance.
|
||||||
*
|
*
|
||||||
* @param string $socialSecurityNumber
|
* @param string|null $socialSecurityNumber
|
||||||
* @return \Tests\Mocks\User|\Illuminate\Database\Eloquent\Model
|
* @return \Tests\Mocks\User|\Illuminate\Database\Eloquent\Model
|
||||||
*/
|
*/
|
||||||
protected function user(string $socialSecurityNumber): User
|
protected function user(?string $socialSecurityNumber): User
|
||||||
{
|
{
|
||||||
return User::query()->create([
|
return User::query()->create([
|
||||||
'social_security_number' => $socialSecurityNumber,
|
'social_security_number' => $socialSecurityNumber,
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@ class EncryptionTest extends TestCase
|
||||||
'social_security_number' => '123-456-789',
|
'social_security_number' => '123-456-789',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame(
|
static::assertSame(
|
||||||
'123-456-789',
|
'123-456-789',
|
||||||
$user->social_security_number
|
$user->social_security_number
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertNotEmpty(
|
static::assertNotEmpty(
|
||||||
$user->social_security_number_index
|
$user->social_security_number_index
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -41,12 +41,12 @@ class EncryptionTest extends TestCase
|
||||||
{
|
{
|
||||||
$user = $this->user('123-456-789');
|
$user = $this->user('123-456-789');
|
||||||
|
|
||||||
$this->assertNotSame(
|
static::assertNotSame(
|
||||||
'123-456-789',
|
'123-456-789',
|
||||||
$user->getRawOriginal('social_security_number')
|
$user->getRawOriginal('social_security_number')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertNotEmpty(
|
static::assertNotEmpty(
|
||||||
$user->social_security_number_index
|
$user->social_security_number_index
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -78,12 +78,12 @@ class EncryptionTest extends TestCase
|
||||||
])
|
])
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
$this->assertNotSame(
|
static::assertNotSame(
|
||||||
'123-456-789',
|
'123-456-789',
|
||||||
$user->getRawOriginal('social_security_number')
|
$user->getRawOriginal('social_security_number')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertNotEmpty(
|
static::assertNotEmpty(
|
||||||
$user->getAttribute('custom_index')
|
$user->getAttribute('custom_index')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -100,9 +100,29 @@ class EncryptionTest extends TestCase
|
||||||
{
|
{
|
||||||
$user = $this->user('123-456-789');
|
$user = $this->user('123-456-789');
|
||||||
|
|
||||||
$this->assertSame(
|
static::assertSame(
|
||||||
'123-456-789',
|
'123-456-789',
|
||||||
$user->getAttribute('social_security_number')
|
$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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertNotContains($userTwo->id, $keys);
|
static::assertNotContains($userTwo->id, $keys);
|
||||||
|
|
||||||
// Assert success using provided index.
|
// Assert success using provided index.
|
||||||
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
||||||
|
|
@ -44,8 +44,8 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertNotContains($userTwo->id, $keys);
|
static::assertNotContains($userTwo->id, $keys);
|
||||||
|
|
||||||
// Assert undefined index exception.
|
// Assert undefined index exception.
|
||||||
$this->expectException(Exception::class);
|
$this->expectException(Exception::class);
|
||||||
|
|
@ -57,6 +57,22 @@ class QueryTest extends TestCase
|
||||||
->get();
|
->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
|
public function testCanQueryEncryptedAttributeWithOrWhereClause(): void
|
||||||
{
|
{
|
||||||
$userOne = $this->user('123-456-789');
|
$userOne = $this->user('123-456-789');
|
||||||
|
|
@ -71,9 +87,9 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertNotContains($userTwo->id, $keys);
|
static::assertNotContains($userTwo->id, $keys);
|
||||||
$this->assertContains($userThree->id, $keys);
|
static::assertContains($userThree->id, $keys);
|
||||||
|
|
||||||
// Assert success using provided index.
|
// Assert success using provided index.
|
||||||
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
||||||
|
|
@ -85,9 +101,9 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertNotContains($userTwo->id, $keys);
|
static::assertNotContains($userTwo->id, $keys);
|
||||||
$this->assertContains($userThree->id, $keys);
|
static::assertContains($userThree->id, $keys);
|
||||||
|
|
||||||
// Assert undefined index exception.
|
// Assert undefined index exception.
|
||||||
$this->expectException(Exception::class);
|
$this->expectException(Exception::class);
|
||||||
|
|
@ -118,9 +134,9 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertContains($userTwo->id, $keys);
|
static::assertContains($userTwo->id, $keys);
|
||||||
$this->assertNotContains($userThree->id, $keys);
|
static::assertNotContains($userThree->id, $keys);
|
||||||
|
|
||||||
// Assert success using provided index.
|
// Assert success using provided index.
|
||||||
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
||||||
|
|
@ -136,9 +152,9 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertContains($userTwo->id, $keys);
|
static::assertContains($userTwo->id, $keys);
|
||||||
$this->assertNotContains($userThree->id, $keys);
|
static::assertNotContains($userThree->id, $keys);
|
||||||
|
|
||||||
$keys = User::query()
|
$keys = User::query()
|
||||||
->whereInEncrypted(
|
->whereInEncrypted(
|
||||||
|
|
@ -149,7 +165,7 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertEmpty($keys);
|
static::assertEmpty($keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCanQueryEncryptedAttributeWithOrWhereInClause(): void
|
public function testCanQueryEncryptedAttributeWithOrWhereInClause(): void
|
||||||
|
|
@ -172,9 +188,9 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertContains($userTwo->id, $keys);
|
static::assertContains($userTwo->id, $keys);
|
||||||
$this->assertNotContains($userThree->id, $keys);
|
static::assertNotContains($userThree->id, $keys);
|
||||||
|
|
||||||
// Assert success using provided index.
|
// Assert success using provided index.
|
||||||
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
/** @var \Illuminate\Database\Eloquent\Collection $keys */
|
||||||
|
|
@ -192,9 +208,9 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertContains($userOne->id, $keys);
|
static::assertContains($userOne->id, $keys);
|
||||||
$this->assertContains($userTwo->id, $keys);
|
static::assertContains($userTwo->id, $keys);
|
||||||
$this->assertNotContains($userThree->id, $keys);
|
static::assertNotContains($userThree->id, $keys);
|
||||||
|
|
||||||
$keys = User::query()
|
$keys = User::query()
|
||||||
->whereInEncrypted(
|
->whereInEncrypted(
|
||||||
|
|
@ -210,6 +226,6 @@ class QueryTest extends TestCase
|
||||||
->get()
|
->get()
|
||||||
->modelKeys();
|
->modelKeys();
|
||||||
|
|
||||||
$this->assertEmpty($keys);
|
static::assertEmpty($keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue