Skip to content

Commit

Permalink
Merge pull request #623 from bugsnag/redacted-keys
Browse files Browse the repository at this point in the history
Add new 'redacted keys' config option to replace 'filters'
  • Loading branch information
imjoehaines committed Feb 8, 2021
2 parents 1364efe + 9dfc80d commit 4cc4bf9
Show file tree
Hide file tree
Showing 11 changed files with 437 additions and 12 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
with:
php-version: ${{ matrix.php-version }}
coverage: none
extensions: intl, mbstring

- run: composer validate

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ Changelog
* Add a "discard classes" configuration option that allows events to be discarded based on the exception class name or PHP error name
[#622](https://github.com/bugsnag/bugsnag-php/pull/622)

* Add a "redacted keys" configuration option. This is similar to `filters` but allows both strings and regexes. String matching is exact but case-insensitive. Regex matching allows for partial and wildcard matching.
[#623](https://github.com/bugsnag/bugsnag-php/pull/623)

### Deprecations

* The `filters` configuration option is now deprecated as `redactedKeys` can express everything that filters could and more.

## 3.25.0 (2020-11-25)

### Enhancements
Expand Down
30 changes: 29 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ public function shouldNotify()
*
* Eg. ['password', 'credit_card'].
*
* @deprecated Use redactedKeys instead
*
* @param string[] $filters an array of metaData filters
*
* @return $this
Expand All @@ -546,7 +548,9 @@ public function setFilters(array $filters)
/**
* Get the array of metaData filters.
*
* @var string
* @deprecated Use redactedKeys instead
*
* @var string[]
*/
public function getFilters()
{
Expand Down Expand Up @@ -987,4 +991,28 @@ public function getDiscardClasses()
{
return $this->config->getDiscardClasses();
}

/**
* Set the array of metadata keys that should be redacted.
*
* @param string[] $redactedKeys
*
* @return $this
*/
public function setRedactedKeys(array $redactedKeys)
{
$this->config->setRedactedKeys($redactedKeys);

return $this;
}

/**
* Get the array of metadata keys that should be redacted.
*
* @var string[]
*/
public function getRedactedKeys()
{
return $this->config->getRedactedKeys();
}
}
39 changes: 38 additions & 1 deletion src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Configuration
/**
* The strings to filter out from metaData.
*
* @deprecated Use redactedKeys instead
*
* @var string[]
*/
protected $filters = [
Expand Down Expand Up @@ -170,6 +172,13 @@ class Configuration
*/
protected $discardClasses = [];

/**
* An array of metadata keys that should be redacted.
*
* @var string[]
*/
protected $redactedKeys = [];

/**
* Create a new config instance.
*
Expand Down Expand Up @@ -261,6 +270,8 @@ public function shouldNotify()
*
* Eg. ['password', 'credit_card'].
*
* @deprecated Use redactedKeys instead
*
* @param string[] $filters an array of metaData filters
*
* @return $this
Expand All @@ -275,7 +286,9 @@ public function setFilters(array $filters)
/**
* Get the array of metaData filters.
*
* @var string
* @deprecated Use redactedKeys instead
*
* @var string[]
*/
public function getFilters()
{
Expand Down Expand Up @@ -836,4 +849,28 @@ public function getDiscardClasses()
{
return $this->discardClasses;
}

/**
* Set the array of metadata keys that should be redacted.
*
* @param string[] $redactedKeys
*
* @return $this
*/
public function setRedactedKeys(array $redactedKeys)
{
$this->redactedKeys = $redactedKeys;

return $this;
}

/**
* Get the array of metadata keys that should be redacted.
*
* @var string[]
*/
public function getRedactedKeys()
{
return $this->redactedKeys;
}
}
20 changes: 15 additions & 5 deletions src/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -785,11 +785,21 @@ protected function cleanupObj($obj, $isMetaData)
*/
protected function shouldFilter($key, $isMetaData)
{
if ($isMetaData) {
foreach ($this->config->getFilters() as $filter) {
if (stripos($key, $filter) !== false) {
return true;
}
if (!$isMetaData) {
return false;
}

foreach ($this->config->getFilters() as $filter) {
if (stripos($key, $filter) !== false) {
return true;
}
}

foreach ($this->config->getRedactedKeys() as $redactedKey) {
if (@preg_match($redactedKey, $key) === 1) {
return true;
} elseif (Utils::stringCaseEquals($redactedKey, $key)) {
return true;
}
}

Expand Down
48 changes: 48 additions & 0 deletions src/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Bugsnag;

use Normalizer;

class Utils
{
/**
Expand Down Expand Up @@ -40,4 +42,50 @@ public static function getBuilderName()

return $builderName;
}

/**
* Check if two strings are equal, ignoring case.
*
* @param string $a
* @param string $b
*
* @return bool
*/
public static function stringCaseEquals($a, $b)
{
// Avoid unicode normalisation and MB comparison if possible
if (strcasecmp($a, $b) === 0) {
return true;
}

// Normalise code points into their decomposed form. For example "ñ"
// can be a single code point (U+00F1) or "n" (U+006E) with a combining
// tilde (U+0303). The decomposed form will always represent this as
// U+006E and U+0303, which means we'll match strings more accurately
// and makes case-insensitive comparisons easier
if (function_exists('normalizer_is_normalized')
&& function_exists('normalizer_normalize')
) {
$form = Normalizer::NFD;

if (!normalizer_is_normalized($a, $form)) {
$a = normalizer_normalize($a, $form);
}

if (!normalizer_is_normalized($b, $form)) {
$b = normalizer_normalize($b, $form);
}
}

if (function_exists('mb_stripos') && function_exists('mb_strlen')) {
// There's no MB equivalent to strcasecmp, so we have to use
// mb_stripos with a length check instead
return mb_strlen($a) === mb_strlen($b) && mb_stripos($a, $b) === 0;
}

// If the MB extension isn't available we can still use strcasecmp
// This will still work for multi-byte strings in some cases because
// the strings were normalised
return strcasecmp($a, $b) === 0;
}
}
14 changes: 14 additions & 0 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,20 @@ public function testDiscardClassesCanBeSet()
$this->assertSame($discardClasses, $this->client->getDiscardClasses());
}

public function testRedactedKeysDefault()
{
$this->assertSame([], $this->client->getRedactedKeys());
}

public function testRedactedKeysCanBeSet()
{
$redactedKeys = ['password', 'password_confirmation'];

$this->client->setRedactedKeys($redactedKeys);

$this->assertSame($redactedKeys, $this->client->getRedactedKeys());
}

private function getGuzzleOption($guzzle, $name)
{
if (GuzzleCompat::isUsingGuzzle5()) {
Expand Down
14 changes: 14 additions & 0 deletions tests/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,18 @@ public function testDiscardClassesCanBeSet()

$this->assertSame($discardClasses, $this->config->getDiscardClasses());
}

public function testRedactedKeysDefault()
{
$this->assertSame([], $this->config->getRedactedKeys());
}

public function testRedactedKeysCanBeSet()
{
$redactedKeys = ['password', 'password_confirmation'];

$this->config->setRedactedKeys($redactedKeys);

$this->assertSame($redactedKeys, $this->config->getRedactedKeys());
}
}

0 comments on commit 4cc4bf9

Please sign in to comment.