Last active
April 13, 2023 05:21
-
-
Save mingalevme/1beec319c17286df76afad068ee00c76 to your computer and use it in GitHub Desktop.
Laravel Sentry Data Sanitizer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Providers; | |
use App\Helpers\SentrySanitizeDataOnBeforeSendListener; | |
use Illuminate\Contracts\Config\Repository as ConfigRepository; | |
use Illuminate\Contracts\Foundation\CachesConfiguration; | |
use Sentry\Event as SentryEvent; | |
use Sentry\EventHint as SentryEventHint; | |
use Sentry\Laravel\ServiceProvider as SentryServiceProvider; | |
final class AppServiceProvider extends AbstractServiceProvider | |
{ | |
public function register(): void | |
{ | |
// Sentry | |
if (!($this->app instanceof CachesConfiguration && $this->app->configurationIsCached())) { | |
$this->app->when(SentrySanitizeDataOnBeforeSendListener::class) | |
->needs('$secretNameList') | |
->give( | |
fn (): array => array_filter( | |
explode(',', $this->getStrEnv('SENTRY_SANITIZE_DATA') ?: ''), | |
) ?: ['token', 'password'], | |
); | |
/** @var ConfigRepository $config */ | |
$config = $this->app->make('config'); | |
$config->set( | |
SentryServiceProvider::$abstract, | |
array_merge([ | |
'before_send' => function (SentryEvent $event, ?SentryEventHint $hint): SentryEvent { | |
$listener = $this->getContainerEntry(SentrySanitizeDataOnBeforeSendListener::class); | |
return $listener->onBeforeSend($event, $hint); | |
}, | |
], (array)$config->get(SentryServiceProvider::$abstract, [])), | |
); | |
} | |
// ... | |
} | |
/** | |
* @template T of object | |
* @param class-string<T> $id | |
* @return T | |
*/ | |
protected function getContainerEntry(string $id): object | |
{ | |
/** @var T $entry */ | |
$entry = $this->app->get($id); | |
return $entry; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Helpers; | |
use Sentry\Event; | |
use Sentry\EventHint; | |
final class SentrySanitizeDataOnBeforeSendListener | |
{ | |
/** | |
* @param list<non-empty-string> $secretNameList | |
*/ | |
public function __construct( | |
private readonly array $secretNameList, | |
) { | |
} | |
public function onBeforeSend(Event $event, ?EventHint $hint): Event | |
{ | |
/** @var array{query_string?: ?string, data?: array<string, mixed>} $request */ | |
$request = $event->getRequest(); | |
if (!empty($request['query_string'])) { | |
foreach ($this->secretNameList as $secretName) { | |
$request['query_string'] = | |
preg_replace( | |
"/$secretName=([^&?]+)/", | |
"$secretName=%5BFiltered%5D", | |
$request['query_string'], | |
); | |
} | |
} | |
if (!empty($request['data'])) { | |
foreach ($this->secretNameList as $secretName) { | |
if (!empty($request['data'][$secretName])) { | |
$request['data'][$secretName] = '[Filtered]'; | |
} | |
} | |
} | |
$event->setRequest($request); | |
return $event; | |
} | |
public static function call(Event $event, ?EventHint $hint): Event | |
{ | |
/** @var SentrySanitizeDataOnBeforeSendListener $self */ | |
$self = app(self::class); | |
return $self->onBeforeSend($event, $hint); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tests\Suites\Feature; | |
use App\Helpers\SentrySanitizeDataOnBeforeSendListener; | |
use Sentry\Event; | |
use Sentry\EventId; | |
use Tests\TestCase; | |
/** | |
* @see SentrySanitizeDataOnBeforeSendListener | |
*/ | |
final class SentrySanitizeDataOnBeforeSendListenerTest extends TestCase | |
{ | |
public function test(): void | |
{ | |
$event = Event::createEvent(EventId::generate()); | |
$payload = [ | |
'foo' => 'bar', | |
'token' => 'token', | |
'password' => 'password', | |
]; | |
$event->setRequest([ | |
'query_string' => http_build_query($payload), | |
'data' => $payload, | |
]); | |
/** | |
* @var Event $event | |
* @see SentrySanitizeDataOnBeforeSendListener::call() | |
*/ | |
$event = [SentrySanitizeDataOnBeforeSendListener::class, 'call']($event, null); | |
self::assertSame(http_build_query(array_merge($payload, [ | |
'token' => '[Filtered]', | |
'password' => '[Filtered]', | |
])), $event->getRequest()['query_string'] ?? null); | |
self::assertSame('bar', $event->getRequest()['data']['foo'] ?? null); | |
self::assertSame('[Filtered]', $event->getRequest()['data']['token'] ?? null); | |
self::assertSame('[Filtered]', $event->getRequest()['data']['password'] ?? null); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment