Completed
Pull Request — master (#9177)
by Morris
73:49 queued 49:19
created

ExceptionSerializer   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 115
rs 10
c 0
b 0
f 0
wmc 14
lcom 1
cbo 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A filterTrace() 0 17 3
A removeValuesFromArgs() 0 10 4
A encodeTrace() 0 7 1
A encodeArg() 0 11 3
A serializeException() 0 20 3
1
<?php
2
/**
3
 * @copyright Copyright (c) 2018 Robin Appelman <[email protected]>
4
 *
5
 * @license GNU AGPL version 3 or any later version
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as
9
 * published by the Free Software Foundation, either version 3 of the
10
 * License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
namespace OC\Log;
23
24
use OC\HintException;
25
26
class ExceptionSerializer {
27
	const methodsWithSensitiveParameters = [
28
		// Session/User
29
		'completeLogin',
30
		'login',
31
		'checkPassword',
32
		'checkPasswordNoLogging',
33
		'loginWithPassword',
34
		'updatePrivateKeyPassword',
35
		'validateUserPass',
36
		'loginWithToken',
37
		'{closure}',
38
39
		// TokenProvider
40
		'getToken',
41
		'isTokenPassword',
42
		'getPassword',
43
		'decryptPassword',
44
		'logClientIn',
45
		'generateToken',
46
		'validateToken',
47
48
		// TwoFactorAuth
49
		'solveChallenge',
50
		'verifyChallenge',
51
52
		// ICrypto
53
		'calculateHMAC',
54
		'encrypt',
55
		'decrypt',
56
57
		// LoginController
58
		'tryLogin',
59
		'confirmPassword',
60
61
		// LDAP
62
		'bind',
63
		'areCredentialsValid',
64
		'invokeLDAPMethod',
65
66
		// Encryption
67
		'storeKeyPair',
68
		'setupUser',
69
	];
70
71
	private function filterTrace(array $trace) {
72
		$sensitiveValues = [];
73
		$trace = array_map(function (array $traceLine) use (&$sensitiveValues) {
74
			foreach (self::methodsWithSensitiveParameters as $sensitiveMethod) {
75
				if (strpos($traceLine['function'], $sensitiveMethod) !== false) {
76
					$sensitiveValues = array_merge($sensitiveValues, $traceLine['args']);
77
					$traceLine['args'] = ['*** sensitive parameters replaced ***'];
78
					return $traceLine;
79
				}
80
			}
81
			return $traceLine;
82
		}, $trace);
83
		return array_map(function (array $traceLine) use ($sensitiveValues) {
84
			$traceLine['args'] = $this->removeValuesFromArgs($traceLine['args'], $sensitiveValues);
85
			return $traceLine;
86
		}, $trace);
87
	}
88
89
	private function removeValuesFromArgs($args, $values) {
90
		foreach ($args as &$arg) {
91
			if (in_array($arg, $values, true)) {
92
				$arg = '*** sensitive parameter replaced ***';
93
			} else if (is_array($arg)) {
94
				$arg = $this->removeValuesFromArgs($arg, $values);
95
			}
96
		}
97
		return $args;
98
	}
99
100
	private function encodeTrace($trace) {
101
		$filteredTrace = $this->filterTrace($trace);
102
		return array_map(function (array $line) {
103
			$line['args'] = array_map([$this, 'encodeArg'], $line['args']);
104
			return $line;
105
		}, $filteredTrace);
106
	}
107
108
	private function encodeArg($arg) {
109
		if (is_object($arg)) {
110
			$data = get_object_vars($arg);
111
			$data['__class__'] = get_class($arg);
112
			return array_map([$this, 'encodeArg'], $data);
113
		} else if (is_array($arg)) {
114
			return array_map([$this, 'encodeArg'], $arg);
115
		} else {
116
			return $arg;
117
		}
118
	}
119
120
	public function serializeException(\Throwable $exception) {
121
		$data = [
122
			'Exception' => get_class($exception),
123
			'Message' => $exception->getMessage(),
124
			'Code' => $exception->getCode(),
125
			'Trace' => $this->encodeTrace($exception->getTrace()),
126
			'File' => $exception->getFile(),
127
			'Line' => $exception->getLine(),
128
		];
129
130
		if ($exception instanceof HintException) {
131
			$data['Hint'] = $exception->getHint();
132
		}
133
134
		if ($exception->getPrevious()) {
135
			$data['Previous'] = $this->serializeException($exception->getPrevious());
136
		}
137
138
		return $data;
139
	}
140
}