| 1: | <?php |
| 2: | namespace Worldline\Connect\Sdk\Logging; |
| 3: | |
| 4: | use UnexpectedValueException; |
| 5: | |
| 6: | |
| 7: | |
| 8: | |
| 9: | |
| 10: | |
| 11: | class BodyObfuscator |
| 12: | { |
| 13: | const MIME_APPLICATION_JSON = 'application/json'; |
| 14: | |
| 15: | |
| 16: | protected $valueObfuscator; |
| 17: | |
| 18: | |
| 19: | private $customRules = array(); |
| 20: | |
| 21: | public function __construct() |
| 22: | { |
| 23: | $this->valueObfuscator = new ValueObfuscator(); |
| 24: | } |
| 25: | |
| 26: | |
| 27: | |
| 28: | |
| 29: | |
| 30: | |
| 31: | public function obfuscateBody($contentType, $body) |
| 32: | { |
| 33: | if (!$this->isJsonContentType($contentType)) { |
| 34: | return $body; |
| 35: | } |
| 36: | $decodedJsonBody = json_decode($body); |
| 37: | if (json_last_error() !== JSON_ERROR_NONE) { |
| 38: | return $body; |
| 39: | } |
| 40: | return json_encode($this->obfuscateDecodedJsonPart($decodedJsonBody), JSON_PRETTY_PRINT); |
| 41: | } |
| 42: | |
| 43: | private function isJsonContentType($contentType) { |
| 44: | return $contentType === static::MIME_APPLICATION_JSON |
| 45: | || substr($contentType, 0, strlen(static::MIME_APPLICATION_JSON)) === static::MIME_APPLICATION_JSON; |
| 46: | } |
| 47: | |
| 48: | |
| 49: | |
| 50: | |
| 51: | |
| 52: | protected function obfuscateDecodedJsonPart($value) |
| 53: | { |
| 54: | if (is_object($value)) { |
| 55: | foreach ($value as $propertyName => $propertyValue) { |
| 56: | if (is_scalar($propertyValue)) { |
| 57: | $value->$propertyName = $this->obfuscateScalarValue($propertyName, $propertyValue); |
| 58: | } else { |
| 59: | $value->$propertyName = $this->obfuscateDecodedJsonPart($propertyValue); |
| 60: | } |
| 61: | } |
| 62: | } |
| 63: | if (is_array($value)) { |
| 64: | foreach ($value as $elementKey => &$elementValue) { |
| 65: | if (is_scalar($elementValue)) { |
| 66: | $elementValue = $this->obfuscateScalarValue($elementKey, $elementValue); |
| 67: | } else { |
| 68: | $elementValue = $this->obfuscateDecodedJsonPart($elementValue); |
| 69: | } |
| 70: | } |
| 71: | |
| 72: | } |
| 73: | return $value; |
| 74: | } |
| 75: | |
| 76: | |
| 77: | |
| 78: | |
| 79: | |
| 80: | |
| 81: | protected function obfuscateScalarValue($key, $value) |
| 82: | { |
| 83: | if (!is_scalar($value)) { |
| 84: | throw new UnexpectedValueException('scalar value expected'); |
| 85: | } |
| 86: | $lowerKey = mb_strtolower(strval($key), 'UTF-8'); |
| 87: | if (isset($this->customRules[$lowerKey])) { |
| 88: | return call_user_func($this->customRules[$lowerKey], $value, $this->valueObfuscator); |
| 89: | } |
| 90: | switch ($lowerKey) { |
| 91: | case 'keyid': |
| 92: | case 'secretkey': |
| 93: | case 'publickey': |
| 94: | case 'userauthenticationtoken': |
| 95: | case 'encryptedpayload': |
| 96: | case 'decryptedpayload': |
| 97: | case 'encryptedcustomerinput': |
| 98: | return $this->valueObfuscator->obfuscateFixedLength(8); |
| 99: | case 'cvv': |
| 100: | case 'value': |
| 101: | return $this->valueObfuscator->obfuscateAll($value); |
| 102: | case 'bin': |
| 103: | return $this->valueObfuscator->obfuscateAllKeepStart($value, 6); |
| 104: | case 'accountnumber': |
| 105: | case 'cardnumber': |
| 106: | case 'iban': |
| 107: | case 'reformattedaccountnumber': |
| 108: | return $this->valueObfuscator->obfuscateAllKeepEnd($value, 4); |
| 109: | case 'expirydate': |
| 110: | return $this->valueObfuscator->obfuscateAllKeepEnd($value, 2); |
| 111: | default: |
| 112: | return $value; |
| 113: | } |
| 114: | } |
| 115: | |
| 116: | |
| 117: | |
| 118: | |
| 119: | |
| 120: | public function setCustomRule($propertyName, callable $customRule) |
| 121: | { |
| 122: | $lowerName = mb_strtolower(strval($propertyName), 'UTF-8'); |
| 123: | $this->customRules[$lowerName] = $customRule; |
| 124: | } |
| 125: | } |
| 126: | |