, (*1)
GDPR compliant data handling with ease
This package helps you get compliant with GDPR;, (*2)
Article 7: Conditions for consent
Article 17: Right to be forgotten
Article 20: Right to data portability
, (*3)
Table of contents
* Table of contents
* Dependencies
* Installation
* Configuration
* Consent
* Portability
* Anonymizability
* Automatic anonymization
* Configuring Anonymizable Data
* Recursive Anonymization
* Configuring Portable Data
* Lazy Eager Loading Relationships
* Hiding Attributes
* Usage
* Encryption
* Anonymization
* Tests
* Security Vulnerabilities
* Credit
* License
, (*4)
Dependencies
- PHP >= 7.0.0
- Laravel >= 5.5
Installation
First, install the package via the Composer package manager:, (*5)
$ composer require dialect/laravel-gdpr-compliance
After installing the package, you should publish the configuration file:, (*6)
$ php artisan vendor:publish --provider="Dialect\Gdpr\GdprServiceProvider" --tag=gdpr-config
Configuration
GDPR Consent
The package includes a way for users to sign a GDPR-agreement. This will redirect the user to the agreement on the specified routes
until the user has agreed to the new terms., (*7)
To add the agreement functionality:, (*8)
- Publish the middleware:
php artisan vendor:publish --provider="Dialect\Gdpr\GdprServiceProvider"
- Add
'gdpr.terms' => \App\Http\Middleware\RedirectIfUnansweredTerms::class
to the $routeMiddleware
middlewaregroup in app/Http/Kernel
like so:
php
protected $routeMiddleware = [
'gdpr.terms' => \App\Http\Middleware\RedirectIfUnansweredTerms::class,
];
- Add the middleware to the routes that you want to check (normally the routes where auth is used):
php
Route::group(['middleware' => ['auth', 'gdpr.terms']], function () {
Route::get('/', 'HomeController@index');
});
- Add the fields to
$fillable
in the User model:
php
protected $fillable = [
'last_activity',
'accepted_gdpr',
'isAnonymized'
];
- Change the Agreement text to your particular needs in
resources/views/gdpr/message.blade.php
Portability
Add the Portable
trait to the model model you want to be able to port:, (*9)
namespace App;
use Dialect\Gdpr\Portable;
class User extends Model
{
use Portable;
}
Anonymizability
Add the Anonymizable
trait to the model you want to be able to anonymize:, (*10)
namespace App;
use Dialect\Gdpr\Anonymizable;
class User extends Model
{
use Anonymizable;
}
Automatic Anonymization of inactive users
The package adds a scheduled job intended to anonymize the User
model automatically when the user has been inactive for a specific time.
To specify the time, edit the ttl
setting in the published config.
To activate this feature:
1. Add the command to the schedule function in app/Console/Kernel.php
like so:, (*11)
```php
protected function schedule(Schedule $schedule)
{
$schedule->command('gdpr:anonymizeInactiveUsers')->daily();
}
```
2. Add the class to the $commands
array in the same file like so:, (*12)
```php
protected $commands = [
\Dialect\Gdpr\Commands\AnonymizeInactiveUsers::class,
];
```
Configuring Anonymizable Data
On the model, set gdprAnonymizableFields
by adding the fields you want to anonymize on the model,
you can also set up attribute-like functions on your model to supply replacement data.
If you have a unique-constraint on your model, you should use this.
If no value is supplied,
a default string from settings will be used., (*13)
/**
* Using the default string from config.
*/
protected $gdprAnonymizableFields = [
'name',
'email'
];
```php
/**
* Using replacement strings.
*/
protected $gdprAnonymizableFields = [
'name' => 'Anonymized User',
'email' => 'anonymous@mail.com'
];, (*14)
```php
namespace App;
use Dialect\Gdpr\Anonymizable;
class User extends Model
{
use Anonymizable;
protected $gdprAnonymizableFields = [
'email'
];
/**
* Using getAnonymized{column} to return anonymizable data
*/
public function getAnonymizedEmail()
{
return random_bytes(10);
}
}
Recursive Anonymization
If the model has related models with fields that needs to be anonymized at the same time,
add the related models to $gdprWith
. On the related models. add the Anonymizable
trait and specify the fields with $gdprAnonymizableFields
like so:, (*15)
class Order extends Model
{
use Anonymizable;
protected $guarded = [];
protected $table = 'orders';
protected $gdprWith = ['product'];
protected $gdprAnonymizableFields = ['buyer' => 'Anonymized Buyer'];
public function product()
{
return $this->belongsTo(Product::class);
}
public function customer()
{
return $this->belongsTo(Customer::class);
}
}
```php
class Customer extends Model
{
use Anonymizable;
protected $guarded = [];
protected $table = 'customers';
protected $gdprWith = ['orders'];, (*16)
protected $gdprAnonymizableFields = ['name' => 'Anonymized User'];
public function orders()
{
return $this->hasMany(Order::class);
}
}, (*17)
Calling `$customer->anonymize();` will also change the `buyer`-field on the related orders.
### Configuring Portable Data
By default, the entire `toArray` form of the `App\User` model will be made available for download. If you would like to customize the downloadable data, you may override the `toPortableArray()` method on the model:
```php
use Dialect\Gdpr\Portable;
class User extends Model
{
use Portable;
/**
* Get the GDPR compliant data portability array for the model.
*
* @return array
*/
public function toPortableArray()
{
$array = $this->toArray();
// Customize array...
return $array;
}
}
Lazy Eager Loading Relationships
You may need to include a relationship in the data that will be made available for download. To do so, add a $gdprWith
property to your App\User
model:, (*18)
use Dialect\Gdpr\Portable;
class User extends Model
{
use Portable;
/**
* The relations to include in the downloadable data.
*
* @var array
*/
protected $gdprWith = ['posts'];
}
Hiding Attributes
You may wish to limit the attributes, such as passwords, that are included in the downloadable data. To do so, add a $gdprHidden
property to your App\User
model:, (*19)
use Dialect\Gdpr\Portable;
class User extends Model
{
use Portable;
/**
* The attributes that should be hidden for the downloadable data.
*
* @var array
*/
protected $gdprHidden = ['password'];
}
Alternatively, you may use the $gdprVisible
property to define a white-list of attributes that should be included in the data that will be made available for download. All other attributes will be hidden when the model is converted:, (*20)
use Dialect\Gdpr\Portable;
class User extends Moeld
{
use Portable;
/**
* The attributes that should be visible in the downloadable data.
*
* @var array
*/
protected $gdprVisible = ['name', 'email'];
}
Usage
This package exposes an endpoint at /gdpr/download
. Only authenticated users should be able to access the routes. Your application should make a POST call, containing the currently authenticated user's password, to this endpoint. The re-authentication is needed to prevent information leakage., (*21)
Encryption
Before using encryption, you must set a key
option in your config/app.php
configuration file. If this value is not properly set, all encrypted values will be insecure., (*22)
You may encrypt/decrypt attributes on the fly using the EncryptsAttributes
trait on any model.
The trait expects the $encrypted
property to be filled with attribute keys:, (*23)
use Dialect\Gdpr\EncryptsAttributes;
class User extends Model
{
use EncryptsAttributes;
/**
* The attributes that should be encrypted and decrypted on the fly.
*
* @var array
*/
protected $encrypted = ['ssnumber'];
}
If all fields are encrypted, the model can be returned in decrypted state as an array or collection:, (*24)
$decryptedArray = $this->decryptToArray();
$decryptedCollection = $this->customer->decryptToCollection();
Anonymization
To anonymize a model you call anonymize()
on it:, (*25)
class SomeController extends Controller
{
public function anonymizeAGroupOfUsers() {
$users = User::where('last_activity', '<=', carbon::now()->submonths(config('gdpr.settings.ttl')))->get();
foreach ($users as $user) {
$user->anonymize();
}
}
}
Tests
After installation you can run the package tests from your laravel-root folder with phpunit vendor/Dialect/gdpr
, (*26)
Security Vulnerabilities
If you discover a security vulnerability within this project, please send an e-mail to Dialect via katrineholm@dialect.se. All security vulnerabilities will be promptly addressed., (*27)
Credit
sander3: Author of the original package used as a startingpoint, (*28)
License
This package is open-source software licensed under the MIT license., (*29)