diff --git a/README.md b/README.md index ffc0817..4d7b014 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,45 @@ $logger->info('Completely hidden', ['you_know_nothing' => 'John Snow']); Example.INFO: Completely hidden {"you_know_nothing":"*********"} [] ``` +### Custom format + +Feel free to customize a replacement character `*` and/or provide your own template. + +```php +use Monolog\Handler\StreamHandler; +use RedactSensitive\RedactSensitiveProcessor; + +$sensitive_keys = ['secret' => 2]; + +$processor = new RedactSensitiveProcessor($sensitive_keys, template: '%s(redacted)'); + +$logger = new \Monolog\Logger('Example', [new StreamHandler(STDOUT)]); +$logger->pushProcessor($processor); + +$logger->info('Sensitive', ['secret' => 'my_secret_value']); +``` +```text +Example.INFO: Sensitive {"secret":"my*************(redacted)"} [] +``` + +Custom template allows to discard the masked characters altogether: +```php +use Monolog\Handler\StreamHandler; +use RedactSensitive\RedactSensitiveProcessor; + +$sensitive_keys = ['secret' => 2]; + +$processor = new RedactSensitiveProcessor($sensitive_keys, template: '...'); + +$logger = new \Monolog\Logger('Example', [new StreamHandler(STDOUT)]); +$logger->pushProcessor($processor); + +$logger->info('Sensitive', ['secret' => 'my_secret_value']); +``` +```text +Example.INFO: Sensitive {"secret":"my..."} [] +``` + ### Length limit Use `lengthLimit` to truncate redacted sensitive information, such as lengthy tokens. diff --git a/src/RedactSensitiveProcessor.php b/src/RedactSensitiveProcessor.php index 765ef6e..98aa225 100644 --- a/src/RedactSensitiveProcessor.php +++ b/src/RedactSensitiveProcessor.php @@ -21,6 +21,7 @@ class RedactSensitiveProcessor implements ProcessorInterface private array $sensitiveKeys; private string $replacement; + private string $template; private ?int $lengthLimit; /** @@ -28,12 +29,14 @@ class RedactSensitiveProcessor implements ProcessorInterface * * @param array $sensitiveKeys Keys that should trigger the redaction. * @param string $replacement The replacement character. + * @param string $template Template for replacement characters. * @param int|null $lengthLimit Max length after redaction. */ - public function __construct(array $sensitiveKeys, string $replacement = self::DEFAULT_REPLACEMENT, ?int $lengthLimit = null) + public function __construct(array $sensitiveKeys, string $replacement = self::DEFAULT_REPLACEMENT, string $template = '%s', ?int $lengthLimit = null) { $this->sensitiveKeys = $sensitiveKeys; $this->replacement = $replacement; + $this->template = $template; $this->lengthLimit = $lengthLimit; } @@ -48,8 +51,9 @@ private function redact(string $value, int $length): string { $hidden_length = strlen($value) - abs($length); $hidden = str_repeat($this->replacement, $hidden_length); + $placeholder = sprintf($this->template, $hidden); - $result = substr_replace($value, $hidden, max(0, $length), $hidden_length); + $result = substr_replace($value, $placeholder, max(0, $length), $hidden_length); $result = $length > 0 ? substr($result, 0, $this->lengthLimit) diff --git a/tests/RedactSensitiveTest.php b/tests/RedactSensitiveTest.php index 30b9010..747d8e6 100644 --- a/tests/RedactSensitiveTest.php +++ b/tests/RedactSensitiveTest.php @@ -14,6 +14,22 @@ expect($processor($record)->context)->toBe(['test' => 'foo***']); }); +it('redacts using template', function (): void { + $sensitive_keys = ['test' => 2]; + $processor = new RedactSensitiveProcessor($sensitive_keys, template: '%s(redacted)'); + + $record = $this->getRecord(context: ['test' => 'foobar']); + expect($processor($record)->context)->toBe(['test' => 'fo****(redacted)']); +}); + +it('redacts discarding masked', function (): void { + $sensitive_keys = ['test' => 1]; + $processor = new RedactSensitiveProcessor($sensitive_keys, template: '...'); + + $record = $this->getRecord(context: ['test' => 'foobar123']); + expect($processor($record)->context)->toBe(['test' => 'f...']); +}); + it('truncates masked characters', function (): void { $sensitive_keys = ['test' => 3]; $processor = new RedactSensitiveProcessor($sensitive_keys, lengthLimit: 5);