Skip to content

Commit

Permalink
Extracting MaskSensitiveData into Collection makro (#3)
Browse files Browse the repository at this point in the history
* Extracting MaskSensitiveData into Collection makro

* Fix styling

* Tweaking comment (code ocd)

* Improve MaskSensitiveData and add PHPStan baseline
  • Loading branch information
spekulatius committed Mar 29, 2023
1 parent 7e3a5a1 commit deaf366
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 5 deletions.
23 changes: 22 additions & 1 deletion config/powertools.php
@@ -1,6 +1,27 @@
<?php

// config for Spekulatius/LaravelPowertools
return [

/*
|--------------------------------------------------------------------------
| Masked fields
|--------------------------------------------------------------------------
|
| These properties will be replaced with "[masked]",
| when logged via toLog or the model tracker.
|
*/

'masked_fields' => [
'/password/i',
'/passwd/i',
'/hash/i',
'/checksum/i',
'/salt/i',
'/token/i',
'/key/i',
'/secret/i',
'/acl/i',
],

];
11 changes: 11 additions & 0 deletions phpstan-baseline.neon
@@ -0,0 +1,11 @@
parameters:
ignoreErrors:
-
message: "#^Call to an undefined method Spekulatius\\\\LaravelPowertools\\\\LaravelPowertoolsServiceProvider\\:\\:map\\(\\)\\.$#"
count: 1
path: src/LaravelPowertoolsServiceProvider.php

-
message: "#^Parameter \\#1 \\$pattern of function preg_match expects string, mixed given\\.$#"
count: 1
path: src/LaravelPowertoolsServiceProvider.php
32 changes: 30 additions & 2 deletions src/LaravelPowertoolsServiceProvider.php
Expand Up @@ -2,12 +2,40 @@

namespace Spekulatius\LaravelPowertools;

use Illuminate\Support\Collection;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Spekulatius\LaravelPowertools\Commands\LaravelPowertoolsCommand;

class LaravelPowertoolsServiceProvider extends PackageServiceProvider
{
public function boot(): void
{
// Mask some sensitive data in a collection
Collection::macro('maskSensitiveData', function () {
// Prepare the masked fields regexes for prime time.
$regexes = (array) config('powertools.masked_fields', []);

// Apply the mask to the sensitive data based on the regexes and custom fields
return $this->map(function ($value, $key) use (&$regexes) {
// Early return null - masking this won't make any sense...
if ($value === null) {
return null;
}

// Check if the key matches one of the regexes
foreach ($regexes as $regex) {
if (preg_match($regex, $key)) {
return '[masked]';
}
}

// Return the original value if it's not sensitive
return $value;
});
});
}

public function configurePackage(Package $package): void
{
/*
Expand All @@ -16,8 +44,8 @@ public function configurePackage(Package $package): void
* More info: https://github.com/spatie/laravel-package-tools
*/
$package
->name('laravel-powertools');
// ->hasConfigFile()
->name('laravel-powertools')
->hasConfigFile();
// ->hasViews()
// ->hasMigration('create_laravel-powertools_table')
// ->hasCommand(LaravelPowertoolsCommand::class);
Expand Down
4 changes: 2 additions & 2 deletions src/Traits/ToLog.php
Expand Up @@ -35,8 +35,8 @@ public function toLog(array $data = null): array
// Convert any Carbon instances to dates
->map(fn ($value) => $value instanceof Carbon ? $value->format('Y-m-d H:i:s') : $value)

// Mask any undesirable logging keys (e.g. password, salt, etc.)
->map(fn ($value, $key) => in_array($key, ['password', 'salt']) && ! is_null($value) ? '[masked]' : $value)
// Mask any undesirable data before logging (e.g. password, salt, etc.)
->maskSensitiveData()

// Replace new lines and multi-spaces with single spaces, trim the result.
->map(fn ($value) => is_string($value) ? trim(preg_replace('/(\s*[\r\n]+\s*|\s+)/', ' ', $value)) : $value)
Expand Down
57 changes: 57 additions & 0 deletions tests/MaskSensitiveDataTest.php
@@ -0,0 +1,57 @@
<?php

namespace Spekulatius\LaravelPowertools\Tests;

class MaskSensitiveDataTest extends TestCase
{
public function testMaskSensitiveData()
{
$data = collect([
'username' => 'johndoe',
'password' => 'secret',
'email' => 'johndoe@example.com',
'salt' => '12345',
'phone' => '555-1234',
'group' => 'admin',
'role' => 'superuser',
'token' => 'abc123',
'acl' => 'user',
'api key' => '12345',
'secret key' => 'abcdef',
'public key' => 'ghijkl',
'checksum' => '123456',
]);

$maskedData = $data->maskSensitiveData();

$this->assertEquals('[masked]', $maskedData['password']);
$this->assertEquals('[masked]', $maskedData['salt']);
$this->assertEquals('[masked]', $maskedData['token']);
$this->assertEquals('[masked]', $maskedData['acl']);
$this->assertEquals('[masked]', $maskedData['api key']);
$this->assertEquals('[masked]', $maskedData['secret key']);
$this->assertEquals('[masked]', $maskedData['public key']);
$this->assertEquals('[masked]', $maskedData['checksum']);
$this->assertEquals('johndoe', $maskedData['username']);
$this->assertEquals('johndoe@example.com', $maskedData['email']);
$this->assertEquals('555-1234', $maskedData['phone']);
}

public function testMaskSensitiveDataWithCustomRegex()
{
// Append our custom regex to the configuration.
$config = config('powertools.masked_fields', []);
$config[] = '/authorization/i';
\Illuminate\Support\Facades\Config::set('powertools.masked_fields', $config);

$data = collect([
'username' => 'johndoe',
'authorization' => 'secret',
'email' => 'johndoe@example.com',
]);

$maskedData = $data->maskSensitiveData();

$this->assertEquals('[masked]', $maskedData['authorization']);
}
}

0 comments on commit deaf366

Please sign in to comment.