[ 'run', 'display', 'loadAutoConfig', ], Setup::class => [ 'install' ], Key::class => [ '__construct' ], Client::class => [ 'request', 'delete', 'deleteAsync', 'get', 'getAsync', 'head', 'headAsync', 'options', 'optionsAsync', 'patch', 'post', 'postAsync', 'put', 'putAsync', ], \Redis::class => [ 'auth' ], \RedisCluster::class => [ '__construct' ], 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', ], UserEventsListener::class => [ 'handle', 'onUserCreated', 'onUserLogin', 'onBeforePasswordUpdated', 'onPasswordUpdated', 'onPasswordReset', ], PassphraseService::class => [ 'setPassphraseForUser', ], ]; private function editTrace(array &$sensitiveValues, array $traceLine): array { if (isset($traceLine['args'])) { $sensitiveValues = array_merge($sensitiveValues, $traceLine['args']); } $traceLine['args'] = [self::SENSITIVE_VALUE_PLACEHOLDER]; return $traceLine; } private function filterTrace(array $trace) { $sensitiveValues = []; $trace = array_map(function (array $traceLine) use (&$sensitiveValues) { $className = $traceLine['class'] ?? ''; if ($className && isset($this->methodsWithSensitiveParametersByClass[$className]) && in_array($traceLine['function'], $this->methodsWithSensitiveParametersByClass[$className], true)) { return $this->editTrace($sensitiveValues, $traceLine); } foreach (self::methodsWithSensitiveParameters as $sensitiveMethod) { if (str_contains($traceLine['function'], $sensitiveMethod) || (str_ends_with($sensitiveMethod, '*') && str_starts_with($traceLine['function'], substr($sensitiveMethod, 0, -1)))) { return $this->editTrace($sensitiveValues, $traceLine); } } return $traceLine; }, $trace); return array_map(function (array $traceLine) use ($sensitiveValues) { if (isset($traceLine['args'])) { $traceLine['args'] = $this->removeValuesFromArgs($traceLine['args'], $sensitiveValues); } return $traceLine; }, $trace); } private function removeValuesFromArgs($args, $values): array { $workArgs = []; foreach ($args as $key => $arg) { if (in_array($arg, $values, true)) { $arg = self::SENSITIVE_VALUE_PLACEHOLDER; } elseif (is_array($arg)) { $arg = $this->removeValuesFromArgs($arg, $values); } $workArgs[$key] = $arg; } return $workArgs; } private function encodeTrace($trace) { $trace = array_map(function (array $line) { if (isset($line['args'])) { $line['args'] = array_map([$this, 'encodeArg'], $line['args']); } return $line; }, $trace); return $this->filterTrace($trace); } private function encodeArg($arg, $nestingLevel = 5) { if (is_object($arg)) { if ($nestingLevel === 0) { return [ '__class__' => get_class($arg), '__properties__' => 'Encoding skipped as the maximum nesting level was reached', ]; } $objectInfo = [ '__class__' => get_class($arg) ]; $objectVars = get_object_vars($arg); return array_map(function ($arg) use ($nestingLevel) { return $this->encodeArg($arg, $nestingLevel - 1); }, array_merge($objectInfo, $objectVars)); } if (is_array($arg)) { if ($nestingLevel === 0) { return ['Encoding skipped as the maximum nesting level was reached']; } // 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'; } } return array_map(function ($e) use ($nestingLevel) { return $this->encodeArg($e, $nestingLevel - 1); }, $arg); } return $arg; } public function serializeException(\Throwable $exception): array { $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; } 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); } }