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