2018-04-13 10:39:27 -04:00
|
|
|
<?php
|
2025-06-30 09:04:05 -04:00
|
|
|
|
2018-04-13 10:39:27 -04:00
|
|
|
/**
|
2024-05-23 03:26:56 -04:00
|
|
|
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
|
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
2018-04-13 10:39:27 -04:00
|
|
|
*/
|
|
|
|
|
namespace OC\Log;
|
|
|
|
|
|
2019-05-06 18:19:48 -04:00
|
|
|
use OC\Core\Controller\SetupController;
|
2024-10-07 15:04:49 -04:00
|
|
|
use OC\Http\Client\Client;
|
2020-06-19 07:44:27 -04:00
|
|
|
use OC\Security\IdentityProof\Key;
|
2019-05-06 18:19:48 -04:00
|
|
|
use OC\Setup;
|
2020-12-29 04:50:53 -05:00
|
|
|
use OC\SystemConfig;
|
2021-07-21 05:18:35 -04:00
|
|
|
use OCA\Encryption\Controller\RecoveryController;
|
|
|
|
|
use OCA\Encryption\Controller\SettingsController;
|
|
|
|
|
use OCA\Encryption\Crypto\Crypt;
|
|
|
|
|
use OCA\Encryption\Crypto\Encryption;
|
|
|
|
|
use OCA\Encryption\KeyManager;
|
2024-09-24 17:37:18 -04:00
|
|
|
use OCA\Encryption\Listeners\UserEventsListener;
|
|
|
|
|
use OCA\Encryption\Services\PassphraseService;
|
2021-07-21 05:18:35 -04:00
|
|
|
use OCA\Encryption\Session;
|
2021-06-29 19:20:33 -04:00
|
|
|
use OCP\HintException;
|
2018-04-13 10:39:27 -04:00
|
|
|
|
|
|
|
|
class ExceptionSerializer {
|
2022-06-16 07:50:59 -04:00
|
|
|
public const SENSITIVE_VALUE_PLACEHOLDER = '*** sensitive parameters replaced ***';
|
|
|
|
|
|
2020-04-10 10:54:27 -04:00
|
|
|
public const methodsWithSensitiveParameters = [
|
2018-04-13 10:39:27 -04:00
|
|
|
// Session/User
|
|
|
|
|
'completeLogin',
|
|
|
|
|
'login',
|
|
|
|
|
'checkPassword',
|
|
|
|
|
'checkPasswordNoLogging',
|
|
|
|
|
'loginWithPassword',
|
|
|
|
|
'updatePrivateKeyPassword',
|
|
|
|
|
'validateUserPass',
|
|
|
|
|
'loginWithToken',
|
|
|
|
|
'{closure}',
|
2024-11-08 05:48:22 -05:00
|
|
|
'{closure:*',
|
2018-07-11 08:26:57 -04:00
|
|
|
'createSessionToken',
|
2018-04-13 10:39:27 -04:00
|
|
|
|
2019-01-10 04:46:58 -05:00
|
|
|
// Provisioning
|
|
|
|
|
'addUser',
|
|
|
|
|
|
2018-04-13 10:39:27 -04:00
|
|
|
// TokenProvider
|
|
|
|
|
'getToken',
|
|
|
|
|
'isTokenPassword',
|
|
|
|
|
'getPassword',
|
|
|
|
|
'decryptPassword',
|
|
|
|
|
'logClientIn',
|
|
|
|
|
'generateToken',
|
|
|
|
|
'validateToken',
|
|
|
|
|
|
|
|
|
|
// TwoFactorAuth
|
|
|
|
|
'solveChallenge',
|
|
|
|
|
'verifyChallenge',
|
|
|
|
|
|
|
|
|
|
// ICrypto
|
|
|
|
|
'calculateHMAC',
|
|
|
|
|
'encrypt',
|
|
|
|
|
'decrypt',
|
|
|
|
|
|
|
|
|
|
// LoginController
|
|
|
|
|
'tryLogin',
|
|
|
|
|
'confirmPassword',
|
|
|
|
|
|
|
|
|
|
// LDAP
|
|
|
|
|
'bind',
|
|
|
|
|
'areCredentialsValid',
|
|
|
|
|
'invokeLDAPMethod',
|
|
|
|
|
|
|
|
|
|
// Encryption
|
|
|
|
|
'storeKeyPair',
|
|
|
|
|
'setupUser',
|
2021-01-18 10:09:06 -05:00
|
|
|
'checkSignature',
|
2019-03-12 10:51:38 -04:00
|
|
|
|
2020-07-09 17:39:58 -04:00
|
|
|
// files_external: OCA\Files_External\MountConfig
|
2019-03-12 10:51:38 -04:00
|
|
|
'getBackendStatus',
|
|
|
|
|
|
|
|
|
|
// files_external: UserStoragesController
|
|
|
|
|
'update',
|
2020-12-04 03:22:30 -05:00
|
|
|
|
|
|
|
|
// Preview providers, don't log big data strings
|
|
|
|
|
'imagecreatefromstring',
|
2023-03-01 07:03:47 -05:00
|
|
|
|
|
|
|
|
// text: PublicSessionController, SessionController and ApiService
|
|
|
|
|
'create',
|
|
|
|
|
'close',
|
|
|
|
|
'push',
|
|
|
|
|
'sync',
|
|
|
|
|
'updateSession',
|
|
|
|
|
'mention',
|
|
|
|
|
'loginSessionUser',
|
|
|
|
|
|
2019-05-06 18:19:48 -04:00
|
|
|
];
|
2019-04-30 06:21:12 -04:00
|
|
|
|
2023-06-28 01:53:43 -04:00
|
|
|
public function __construct(
|
|
|
|
|
private SystemConfig $systemConfig,
|
|
|
|
|
) {
|
2020-12-29 04:50:53 -05:00
|
|
|
}
|
|
|
|
|
|
2022-07-28 17:30:17 -04:00
|
|
|
protected array $methodsWithSensitiveParametersByClass = [
|
2019-05-06 18:19:48 -04:00
|
|
|
SetupController::class => [
|
|
|
|
|
'run',
|
|
|
|
|
'display',
|
|
|
|
|
'loadAutoConfig',
|
|
|
|
|
],
|
|
|
|
|
Setup::class => [
|
|
|
|
|
'install'
|
2020-06-19 07:44:27 -04:00
|
|
|
],
|
|
|
|
|
Key::class => [
|
|
|
|
|
'__construct'
|
|
|
|
|
],
|
2024-10-07 15:04:49 -04:00
|
|
|
Client::class => [
|
|
|
|
|
'request',
|
|
|
|
|
'delete',
|
|
|
|
|
'deleteAsync',
|
|
|
|
|
'get',
|
|
|
|
|
'getAsync',
|
|
|
|
|
'head',
|
|
|
|
|
'headAsync',
|
|
|
|
|
'options',
|
|
|
|
|
'optionsAsync',
|
|
|
|
|
'patch',
|
|
|
|
|
'post',
|
|
|
|
|
'postAsync',
|
|
|
|
|
'put',
|
|
|
|
|
'putAsync',
|
|
|
|
|
],
|
2021-07-19 13:52:15 -04:00
|
|
|
\Redis::class => [
|
|
|
|
|
'auth'
|
|
|
|
|
],
|
|
|
|
|
\RedisCluster::class => [
|
|
|
|
|
'__construct'
|
2021-07-21 05:18:35 -04:00
|
|
|
],
|
|
|
|
|
Crypt::class => [
|
|
|
|
|
'symmetricEncryptFileContent',
|
|
|
|
|
'encrypt',
|
|
|
|
|
'generatePasswordHash',
|
|
|
|
|
'encryptPrivateKey',
|
|
|
|
|
'decryptPrivateKey',
|
|
|
|
|
'isValidPrivateKey',
|
|
|
|
|
'symmetricDecryptFileContent',
|
|
|
|
|
'checkSignature',
|
|
|
|
|
'createSignature',
|
|
|
|
|
'decrypt',
|
|
|
|
|
'multiKeyDecrypt',
|
|
|
|
|
'multiKeyEncrypt',
|
|
|
|
|
],
|
|
|
|
|
RecoveryController::class => [
|
|
|
|
|
'adminRecovery',
|
|
|
|
|
'changeRecoveryPassword'
|
|
|
|
|
],
|
|
|
|
|
SettingsController::class => [
|
|
|
|
|
'updatePrivateKeyPassword',
|
|
|
|
|
],
|
|
|
|
|
Encryption::class => [
|
|
|
|
|
'encrypt',
|
|
|
|
|
'decrypt',
|
|
|
|
|
],
|
|
|
|
|
KeyManager::class => [
|
|
|
|
|
'checkRecoveryPassword',
|
|
|
|
|
'storeKeyPair',
|
|
|
|
|
'setRecoveryKey',
|
|
|
|
|
'setPrivateKey',
|
|
|
|
|
'setFileKey',
|
|
|
|
|
'setAllFileKeys',
|
|
|
|
|
],
|
|
|
|
|
Session::class => [
|
|
|
|
|
'setPrivateKey',
|
|
|
|
|
'prepareDecryptAll',
|
|
|
|
|
],
|
|
|
|
|
\OCA\Encryption\Users\Setup::class => [
|
|
|
|
|
'setupUser',
|
|
|
|
|
],
|
2024-09-24 17:37:18 -04:00
|
|
|
UserEventsListener::class => [
|
|
|
|
|
'handle',
|
|
|
|
|
'onUserCreated',
|
|
|
|
|
'onUserLogin',
|
|
|
|
|
'onBeforePasswordUpdated',
|
|
|
|
|
'onPasswordUpdated',
|
|
|
|
|
'onPasswordReset',
|
|
|
|
|
],
|
|
|
|
|
PassphraseService::class => [
|
|
|
|
|
'setPassphraseForUser',
|
2021-07-21 05:18:35 -04:00
|
|
|
],
|
2018-04-13 10:39:27 -04:00
|
|
|
];
|
|
|
|
|
|
2019-05-06 18:19:48 -04:00
|
|
|
private function editTrace(array &$sensitiveValues, array $traceLine): array {
|
2019-11-21 16:25:08 -05:00
|
|
|
if (isset($traceLine['args'])) {
|
|
|
|
|
$sensitiveValues = array_merge($sensitiveValues, $traceLine['args']);
|
|
|
|
|
}
|
2022-06-16 07:50:59 -04:00
|
|
|
$traceLine['args'] = [self::SENSITIVE_VALUE_PLACEHOLDER];
|
2019-05-06 18:19:48 -04:00
|
|
|
return $traceLine;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 10:39:27 -04:00
|
|
|
private function filterTrace(array $trace) {
|
|
|
|
|
$sensitiveValues = [];
|
|
|
|
|
$trace = array_map(function (array $traceLine) use (&$sensitiveValues) {
|
2019-05-08 04:00:33 -04:00
|
|
|
$className = $traceLine['class'] ?? '';
|
2022-07-28 17:30:17 -04:00
|
|
|
if ($className && isset($this->methodsWithSensitiveParametersByClass[$className])
|
|
|
|
|
&& in_array($traceLine['function'], $this->methodsWithSensitiveParametersByClass[$className], true)) {
|
2019-05-06 18:19:48 -04:00
|
|
|
return $this->editTrace($sensitiveValues, $traceLine);
|
|
|
|
|
}
|
2018-04-13 10:39:27 -04:00
|
|
|
foreach (self::methodsWithSensitiveParameters as $sensitiveMethod) {
|
2024-11-08 05:48:22 -05:00
|
|
|
if (str_contains($traceLine['function'], $sensitiveMethod)
|
|
|
|
|
|| (str_ends_with($sensitiveMethod, '*')
|
|
|
|
|
&& str_starts_with($traceLine['function'], substr($sensitiveMethod, 0, -1)))) {
|
2019-05-06 18:19:48 -04:00
|
|
|
return $this->editTrace($sensitiveValues, $traceLine);
|
2018-04-13 10:39:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $traceLine;
|
|
|
|
|
}, $trace);
|
|
|
|
|
return array_map(function (array $traceLine) use ($sensitiveValues) {
|
2018-07-18 08:42:05 -04:00
|
|
|
if (isset($traceLine['args'])) {
|
|
|
|
|
$traceLine['args'] = $this->removeValuesFromArgs($traceLine['args'], $sensitiveValues);
|
|
|
|
|
}
|
2018-04-13 10:39:27 -04:00
|
|
|
return $traceLine;
|
|
|
|
|
}, $trace);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 01:53:43 -04:00
|
|
|
private function removeValuesFromArgs($args, $values): array {
|
2022-06-16 07:30:52 -04:00
|
|
|
$workArgs = [];
|
2024-10-07 15:04:49 -04:00
|
|
|
foreach ($args as $key => $arg) {
|
2018-04-13 10:39:27 -04:00
|
|
|
if (in_array($arg, $values, true)) {
|
2022-06-16 07:50:59 -04:00
|
|
|
$arg = self::SENSITIVE_VALUE_PLACEHOLDER;
|
2020-04-10 04:35:09 -04:00
|
|
|
} elseif (is_array($arg)) {
|
2018-04-13 10:39:27 -04:00
|
|
|
$arg = $this->removeValuesFromArgs($arg, $values);
|
|
|
|
|
}
|
2024-10-07 15:04:49 -04:00
|
|
|
$workArgs[$key] = $arg;
|
2018-04-13 10:39:27 -04:00
|
|
|
}
|
2022-06-16 07:30:52 -04:00
|
|
|
return $workArgs;
|
2018-04-13 10:39:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function encodeTrace($trace) {
|
2023-01-03 13:24:00 -05:00
|
|
|
$trace = array_map(function (array $line) {
|
2018-07-18 08:42:05 -04:00
|
|
|
if (isset($line['args'])) {
|
|
|
|
|
$line['args'] = array_map([$this, 'encodeArg'], $line['args']);
|
|
|
|
|
}
|
2018-04-13 10:39:27 -04:00
|
|
|
return $line;
|
2023-01-03 13:24:00 -05:00
|
|
|
}, $trace);
|
|
|
|
|
return $this->filterTrace($trace);
|
2018-04-13 10:39:27 -04:00
|
|
|
}
|
|
|
|
|
|
2021-08-05 08:58:03 -04:00
|
|
|
private function encodeArg($arg, $nestingLevel = 5) {
|
2018-04-13 10:39:27 -04:00
|
|
|
if (is_object($arg)) {
|
2021-08-05 08:58:03 -04:00
|
|
|
if ($nestingLevel === 0) {
|
|
|
|
|
return [
|
|
|
|
|
'__class__' => get_class($arg),
|
|
|
|
|
'__properties__' => 'Encoding skipped as the maximum nesting level was reached',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-05 09:00:41 -04:00
|
|
|
$objectInfo = [ '__class__' => get_class($arg) ];
|
|
|
|
|
$objectVars = get_object_vars($arg);
|
2021-08-05 08:58:03 -04:00
|
|
|
return array_map(function ($arg) use ($nestingLevel) {
|
|
|
|
|
return $this->encodeArg($arg, $nestingLevel - 1);
|
2021-08-05 09:00:41 -04:00
|
|
|
}, array_merge($objectInfo, $objectVars));
|
2020-12-29 04:50:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_array($arg)) {
|
2021-08-05 08:58:03 -04:00
|
|
|
if ($nestingLevel === 0) {
|
|
|
|
|
return ['Encoding skipped as the maximum nesting level was reached'];
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-29 04:50:53 -05:00
|
|
|
// Only log the first 5 elements of an array unless we are on debug
|
|
|
|
|
if ((int)$this->systemConfig->getValue('loglevel', 2) !== 0) {
|
|
|
|
|
$elemCount = count($arg);
|
|
|
|
|
if ($elemCount > 5) {
|
|
|
|
|
$arg = array_slice($arg, 0, 5);
|
|
|
|
|
$arg[] = 'And ' . ($elemCount - 5) . ' more entries, set log level to debug to see all entries';
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-05 08:58:03 -04:00
|
|
|
return array_map(function ($e) use ($nestingLevel) {
|
|
|
|
|
return $this->encodeArg($e, $nestingLevel - 1);
|
|
|
|
|
}, $arg);
|
2018-04-13 10:39:27 -04:00
|
|
|
}
|
2020-12-29 04:50:53 -05:00
|
|
|
|
|
|
|
|
return $arg;
|
2018-04-13 10:39:27 -04:00
|
|
|
}
|
|
|
|
|
|
2023-06-28 01:53:43 -04:00
|
|
|
public function serializeException(\Throwable $exception): array {
|
2018-04-13 10:39:27 -04:00
|
|
|
$data = [
|
|
|
|
|
'Exception' => get_class($exception),
|
|
|
|
|
'Message' => $exception->getMessage(),
|
|
|
|
|
'Code' => $exception->getCode(),
|
|
|
|
|
'Trace' => $this->encodeTrace($exception->getTrace()),
|
|
|
|
|
'File' => $exception->getFile(),
|
|
|
|
|
'Line' => $exception->getLine(),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ($exception instanceof HintException) {
|
|
|
|
|
$data['Hint'] = $exception->getHint();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($exception->getPrevious()) {
|
|
|
|
|
$data['Previous'] = $this->serializeException($exception->getPrevious());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
2022-07-28 17:30:17 -04:00
|
|
|
|
|
|
|
|
public function enlistSensitiveMethods(string $class, array $methods): void {
|
|
|
|
|
if (!isset($this->methodsWithSensitiveParametersByClass[$class])) {
|
|
|
|
|
$this->methodsWithSensitiveParametersByClass[$class] = [];
|
|
|
|
|
}
|
|
|
|
|
$this->methodsWithSensitiveParametersByClass[$class] = array_merge($this->methodsWithSensitiveParametersByClass[$class], $methods);
|
|
|
|
|
}
|
2018-07-18 08:42:05 -04:00
|
|
|
}
|