Skip to content
This repository has been archived by the owner on Apr 25, 2024. It is now read-only.

Commit

Permalink
Logic for hashing instead of redacting added + code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjustein committed Feb 3, 2024
1 parent 8a55551 commit cb7c139
Showing 1 changed file with 73 additions and 31 deletions.
104 changes: 73 additions & 31 deletions src/HashSensitiveProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class HashSensitiveProcessor implements ProcessorInterface
{
private array $sensitiveKeys;
private ?int $lengthLimit;
private string $algorithm;

/**
* Creates a new HashSensitiveProcessor instance.
Expand All @@ -27,87 +28,128 @@ public function __construct(array $sensitiveKeys, string $algorithm = 'sha256',
{
$this->sensitiveKeys = $sensitiveKeys;
$this->lengthLimit = $lengthLimit;
$this->algorithm = $algorithm;
}


/**
* Invoke hook into the monolog processor execution.
*
* @param LogRecord $record Log record before being processed.
*
* @return LogRecord Log record with redacted values hashed.
*/
public function __invoke(LogRecord $record): LogRecord
{
$redactedContext = $this->traverseInputArray($record->context, $this->sensitiveKeys);
return $record->with(context: $redactedContext);
}

/**
* Function to hash the input value, using the specified hashing algorithm and length limit
*
* @param string $value The value to hash
*
* @return string|null The hashed value, or null, if the input string was empty
*/
private function hash(string $value): ?string
{
if (strlen($value) === 0) {
return null;
}

$hiddenLength = $valueLength - abs($length);
$hidden = str_repeat($this->replacement, $hiddenLength);
$placeholder = sprintf($this->template, $hidden);

$result = substr_replace($value, $placeholder, max(0, $length), $hiddenLength);

return $length > 0
? substr($result, 0, $this->lengthLimit)
: substr($result, -$this->lengthLimit);
// Cut the input to the length limit specified
$cutInput = substr($value, 0, $this->lengthLimit);
return hash($this->algorithm, $cutInput);
}

/**
* @param array|object $value
* @param array|int $keys
* @return array|object
* Function to handle traversing arrays and objects
*
* @param string $key The key being processed
* @param array|object $value The value of the key in the input data
* @param array $sensitiveKeys The list of keys to hash
*
* @throws UnexpectedValueException if $value was not either an array of an object
*
* @return array|object The processed array or object
*/
private function traverse(string $key, $value, $keys)
private function traverse(string $key, array|object $value, array $sensitiveKeys): array|object
{
if (is_array($value)) {
return $this->traverseArr($value, $keys);
return $this->traverseInputArray($value, $sensitiveKeys);
}

if (is_object($value)) {
return $this->traverseObj($value, $keys);
return $this->traverseObject($value, $sensitiveKeys);
}

throw new UnexpectedValueException("Don't know how to traverse value at key $key");
}

/**
* Traverse an array and replace all values to be redacted with a hashed version of the value
*
* @param array $inputArray Array to redact values from
* @param array $sensitiveKeys Keys to redact
*
* @return array Input array with redacted values hashed
*/
private function traverseInputArray(array $inputArray, array $sensitiveKeys): array
{
foreach ($inputArray as $key => $value) {
if ($value === null) {
// Nothing to hash or process
continue;
}

// If the value is not an array or an object, hash it if it is a sensitive key
if (is_scalar($value)) {
if (array_key_exists($key, $sensitiveKeys)) {
$inputArray[$key] = $this->hash((string) $value);
}

continue;
}

// The value is either an array or an object, let traverse handle the specifics
if (array_key_exists($key, $sensitiveKeys)) {
$inputArray[$key] = $this->traverse($key, $value, $sensitiveKeys[$key]);
} else {
if (array_key_exists($key, $sensitiveKeys)) {
$inputArray[$key] = $this->traverse($key, $value, $sensitiveKeys[$key]);
} else {
$inputArray[$key] = $this->traverse($key, $value, $sensitiveKeys);
}
$inputArray[$key] = $this->traverse($key, $value, $sensitiveKeys);
}
}

return $inputArray;
}

private function traverseObj(object $obj, array $keys): object
/**
* Traverse an object and replace all values to be redacted with a hashed version of the value
*
* @param object $object Object to redact values from
* @param array $sensitiveKeys Keys for which to hash the value
*
* @return object The object with redacted values hashed
*/
private function traverseObject(object $object, array $sensitiveKeys): object
{
foreach (get_object_vars($obj) as $key => $value) {
foreach (get_object_vars($object) as $key => $value) {
// If the value is not an array or an object, hash it if it is a sensitive key
if (is_scalar($value)) {
if (array_key_exists($key, $keys)) {
$obj->{$key} = $this->redact((string) $value, $keys[$key]);
if (array_key_exists($key, $sensitiveKeys)) {
$object->{$key} = $this->hash((string) $value);
}

continue;
}

// The value is either an array or an object, let traverse handle the specifics
if (array_key_exists($key, $sensitiveKeys)) {
$object->{$key} = $this->traverse($key, $value, $sensitiveKeys[$key]);
} else {
if (array_key_exists($key, $keys)) {
$obj->{$key} = $this->traverse($key, $value, $keys[$key]);
} else {
$obj->{$key} = $this->traverse($key, $value, $keys);
}
$object->{$key} = $this->traverse($key, $value, $sensitiveKeys);
}
}

return $obj;
return $object;
}
}

0 comments on commit cb7c139

Please sign in to comment.