Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
JaZo committed Mar 4, 2024
1 parent f893b26 commit ef63fbf
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 8 deletions.
1 change: 1 addition & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
'phpdoc_order' => true,
'yoda_style' => false,
'no_superfluous_phpdoc_tags' => false,
'fully_qualified_strict_types' => false,
])
;
39 changes: 39 additions & 0 deletions MIGRATING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Migrating swisnl/laravel-encrypted-data

## To Laravel Encrypted Casting
The main difference between this package and [Laravel Encrypted Casting](https://laravel.com/docs/10.x/eloquent-mutators#encrypted-casting) is that this package serializes the data before encrypting it, while Laravel Encrypted Casting encrypts the data directly. This means that the data is not compatible between the two packages. In order to migrate from this package to Laravel Encrypted Casting, you will need to decrypt the data and then re-encrypt it using Laravel Encrypted Casting. Here is a step-by-step guide on how to do this:

[//]: # (TODO: What to do when you need serialized data?)

1. Set up Encrypted Casting, but keep extending `EncryptedModel` from this package:
```diff
- protected $encrypted = [
- 'secret',
- ];
+ protected $casts = [
+ 'secret' => 'encrypted',
+ ];
```
2. Set up our custom model encrypter in your `AppServiceProvider`:
```php
public function boot(): void
{
$modelEncrypter = new \Swis\Laravel\Encrypted\ModelEncrypter();
YourEncryptedModel::encryptUsing($modelEncrypter);
// ... all your other models that extend \Swis\Laravel\Encrypted\EncryptedModel
}
```
3. Run our re-encryption command:
```bash
php artisan encrypted-data:re-encrypt:models app/Models --quietly --no-touch --with-trashed
```
N.B. Modify options as needed!
4. Remove the `Swis\Laravel\Encrypted\EncryptedModel` from your models and replace it with `Illuminate\Database\Eloquent\Model`:
```diff
- use Swis\Laravel\Encrypted\EncryptedModel
+ use Illuminate\Database\Eloquent\Model

- class YourEncryptedModel extends EncryptedModel
+ class YourEncryptedModel extends Model
```
5. Remove our custom model encrypter from your `AppServiceProvider` (step 2).
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ This package contains several Laravel utilities to work with encrypted data.

Via Composer

``` bash
$ composer require swisnl/laravel-encrypted-data
```bash
composer require swisnl/laravel-encrypted-data
```

N.B. Using Laravel 6-8? Please use version [1.x](https://github.com/swisnl/laravel-encrypted-data/tree/1.x) of this package.
Expand All @@ -33,7 +33,7 @@ N.B. Using Laravel 6-8? Please use version [1.x](https://github.com/swisnl/larav

Extend `\Swis\Laravel\Encrypted\EncryptedModel` in your model and define the encrypted fields. Make sure your database columns are long enough, so your data isn't truncated!

``` php
```php
protected $encrypted = [
'secret',
];
Expand All @@ -45,7 +45,7 @@ You can now simply use the model properties as usual and everything will be encr

Configure the storage driver in `config/filesystems.php`.

``` php
```php
'disks' => [
'local' => [
'driver' => 'local-encrypted',
Expand Down Expand Up @@ -78,8 +78,8 @@ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed re

## Testing

``` bash
$ composer test
```bash
composer test
```

## Contributing
Expand Down
57 changes: 57 additions & 0 deletions src/Commands/ReEncryptModels.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Swis\Laravel\Encrypted\Commands;

use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;

class ReEncryptModels extends Command
{
protected $signature = 'encrypted-data:re-encrypt:models [directory] {--quietly} {--no-touch} {--with-trashed}';

protected $description = 'Re-encrypt models';

public function handle(): int
{
collect($models)
->filter(fn (string $model) => is_a($model, Model::class, true))
->each(
/**
* @param class-string<\Illuminate\Database\Eloquent\Model> $modelClass
*/
function (string $modelClass) {
// with trashed?
$modelClass::query()->eachById(function (Model $model) {
// quietly?
// no-touch?
return $model->save();
});
}
);

return 0;
}

/**
* Get the root namespace for the class.
*
* @return string
*/
protected function rootNamespace()
{
return $this->laravel->getNamespace();
}

/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
*
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return is_dir(app_path('Models')) ? $rootNamespace.'\\Models' : $rootNamespace;
}
}
20 changes: 20 additions & 0 deletions src/EncryptedModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

/**
* @deprecated use Laravel's built-in encrypted casting instead
* @see ../MIGRATING.md for a step-by-step guide on how to migrate
*/
class EncryptedModel extends Model
{
/**
Expand All @@ -28,6 +32,22 @@ public function setRawAttributes(array $attributes, $sync = false)
return parent::setRawAttributes($this->decryptAttributes($attributes), $sync);
}

/**
* {@inheritdoc}
*
* @param string $key
*
* @return bool
*/
public function originalIsEquivalent($key)
{
if (static::$encrypter instanceof ModelEncrypter && $this->isEncryptedCastable($key)) {
return false;
}

return parent::originalIsEquivalent($key);
}

/**
* {@inheritdoc}
*
Expand Down
47 changes: 47 additions & 0 deletions src/ModelEncrypter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Swis\Laravel\Encrypted;

use Illuminate\Contracts\Encryption\Encrypter;

class ModelEncrypter implements Encrypter
{
private ?Encrypter $encrypter;

public function __construct()
{
$this->encrypter = app('encrypted-data.encrypter');
}

public function encrypt($value, $serialize = true)
{
return $this->encrypter->encrypt($value, $serialize);
}

public function decrypt($payload, $unserialize = true)
{
$decrypted = $this->encrypter->decrypt($payload, false);

$unserialized = @unserialize($decrypted);
if ($unserialized === false && $decrypted !== 'b:0;') {
return $decrypted;
}

return $unserialized;
}

public function getKey()
{
return $this->encrypter->getKey();
}

public function getAllKeys()
{
return $this->encrypter->getAllKeys();
}

public function getPreviousKeys()
{
return $this->encrypter->getPreviousKeys();
}
}
4 changes: 2 additions & 2 deletions tests/EncryptedModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public function itEncryptsDataOnUpdate(): void
// expectations
}

private function getModelInstance(Builder $query = null, bool $exists = false): EncryptedModel
private function getModelInstance(?Builder $query = null, bool $exists = false): EncryptedModel
{
return new class($query, $exists) extends EncryptedModel {
protected $guarded = [];
Expand All @@ -135,7 +135,7 @@ private function getModelInstance(Builder $query = null, bool $exists = false):

private $query;

public function __construct(Builder $query = null, $exists = false)
public function __construct(?Builder $query = null, $exists = false)
{
parent::__construct([]);

Expand Down

0 comments on commit ef63fbf

Please sign in to comment.