1: <?php
2: namespace Worldline\Connect\Sdk\Logging;
3:
4: use UnexpectedValueException;
5:
6: /**
7: * Class BodyObfuscator
8: *
9: * @package Worldline\Connect\Sdk\Logging
10: */
11: class BodyObfuscator
12: {
13: const MIME_APPLICATION_JSON = 'application/json';
14:
15: /** @var ValueObfuscator */
16: protected $valueObfuscator;
17:
18: /** @var array<string, callable> */
19: private $customRules = array();
20:
21: public function __construct()
22: {
23: $this->valueObfuscator = new ValueObfuscator();
24: }
25:
26: /**
27: * @param string $contentType
28: * @param string $body
29: * @return string
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: * @param $value
50: * @return mixed
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: * @param $key
78: * @param $value
79: * @return string
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: * @param $propertyName
118: * @param callable $customRule
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: