Skip to content

Commit 24c74f9

Browse files
author
thinkingmedia
committed
adds configurable masking of array/object properties
1 parent 752d0fe commit 24c74f9

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

src/Error/Debugger.php

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
namespace Cake\Error;
1616

17+
use Cake\Core\InstanceConfigTrait;
1718
use Cake\Log\Log;
1819
use Cake\Utility\Hash;
1920
use Cake\Utility\Security;
@@ -32,6 +33,16 @@
3233
*/
3334
class Debugger
3435
{
36+
use InstanceConfigTrait;
37+
38+
/**
39+
* Default configuration
40+
*
41+
* @var array
42+
*/
43+
protected $_defaultConfig = [
44+
'mask' => []
45+
];
3546

3647
/**
3748
* A list of errors generated by the application.
@@ -152,7 +163,7 @@ public function __construct()
152163
* Returns a reference to the Debugger singleton object instance.
153164
*
154165
* @param string|null $class Class name.
155-
* @return object
166+
* @return object|Debugger
156167
*/
157168
public static function getInstance($class = null)
158169
{
@@ -169,6 +180,24 @@ public static function getInstance($class = null)
169180
return $instance[0];
170181
}
171182

183+
/**
184+
* Read or write configuration options for the Debugger instance.
185+
*
186+
* @param string|array|null $key The key to get/set, or a complete array of configs.
187+
* @param mixed|null $value The value to set.
188+
* @param bool $merge Whether to recursively merge or overwrite existing config, defaults to true.
189+
* @return mixed Config value being read, or the object itself on write operations.
190+
* @throws \Cake\Core\Exception\Exception When trying to set a key that is invalid.
191+
*/
192+
public static function configInstance($key = null, $value = null, $merge = true)
193+
{
194+
if (is_array($key) || func_num_args() >= 2) {
195+
return static::getInstance()->config($key, $value, $merge);
196+
}
197+
198+
return static::getInstance()->config($key);
199+
}
200+
172201
/**
173202
* Recursively formats and outputs the contents of the supplied variable.
174203
*
@@ -505,10 +534,13 @@ protected static function _array(array $var, $depth, $indent)
505534
$vars = [];
506535

507536
if ($depth >= 0) {
537+
$mask = (array)static::configInstance('mask');
508538
foreach ($var as $key => $val) {
509539
// Sniff for globals as !== explodes in < 5.4
510540
if ($key === 'GLOBALS' && is_array($val) && isset($val['GLOBALS'])) {
511541
$val = '[recursion]';
542+
} elseif (array_key_exists($key, $mask)) {
543+
$val = (string)$mask[$key];
512544
} elseif ($val !== $var) {
513545
$val = static::_export($val, $depth, $indent);
514546
}
@@ -555,9 +587,10 @@ protected static function _object($var, $depth, $indent)
555587
}
556588

557589
if ($depth > 0) {
590+
$mask = (array)static::configInstance('mask');
558591
$objectVars = get_object_vars($var);
559592
foreach ($objectVars as $key => $value) {
560-
$value = static::_export($value, $depth - 1, $indent);
593+
$value = array_key_exists($key, $mask) ? $mask[$key] : static::_export($value, $depth - 1, $indent);
561594
$props[] = "$key => " . $value;
562595
}
563596

@@ -575,7 +608,12 @@ protected static function _object($var, $depth, $indent)
575608

576609
$value = static::_export($property, $depth - 1, $indent);
577610
$key = $reflectionProperty->name;
578-
$props[] = sprintf('[%s] %s => %s', $visibility, $key, $value);
611+
$props[] = sprintf(
612+
'[%s] %s => %s',
613+
$visibility,
614+
$key,
615+
array_key_exists($key, $mask) ? $mask[$key] : $value
616+
);
579617
}
580618
}
581619

tests/TestCase/Error/DebuggerTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public function __debugInfo()
3636
}
3737
}
3838

39+
class SecurityThing
40+
{
41+
public $password = 'pass1234';
42+
}
43+
3944
/**
4045
* DebuggerTest class
4146
*
@@ -561,4 +566,31 @@ public function testDebugInfo()
561566
eos;
562567
$this->assertEquals($expected, $result);
563568
}
569+
570+
/**
571+
* Tests the masking of an array key.
572+
*
573+
* @return void
574+
*/
575+
public function testMaskArray()
576+
{
577+
Debugger::configInstance('mask', ['password' => '[**********]']);
578+
$result = Debugger::exportVar(['password' => 'pass1234']);
579+
$expected = "['password'=>[**********]]";
580+
$this->assertEquals($expected, preg_replace('/\s+/', '', $result));
581+
}
582+
583+
/**
584+
* Tests the masking of an array key.
585+
*
586+
* @return void
587+
*/
588+
public function testMaskObject()
589+
{
590+
Debugger::configInstance('mask', ['password' => '[**********]']);
591+
$object = new SecurityThing();
592+
$result = Debugger::exportVar($object);
593+
$expected = "object(Cake\\Test\\TestCase\\Error\\SecurityThing){password=>[**********]}";
594+
$this->assertEquals($expected, preg_replace('/\s+/', '', $result));
595+
}
564596
}

0 commit comments

Comments
 (0)