From 972b4ad2adff17c0e34469c36622aba8e67da6c7 Mon Sep 17 00:00:00 2001 From: Oleksander Piskun Date: Sat, 16 May 2026 06:04:28 +0000 Subject: [PATCH] fix: normalize missing bruteforce_protection and headers_to_exclude on ExApp routes Signed-off-by: Oleksander Piskun --- lib/Controller/ExAppProxyController.php | 11 ++++++----- lib/Db/ExAppMapper.php | 12 ++++++++++++ lib/Service/ExAppService.php | 5 ++--- lib/Service/HarpService.php | 7 ++----- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/Controller/ExAppProxyController.php b/lib/Controller/ExAppProxyController.php index b390607a..372f9ff0 100644 --- a/lib/Controller/ExAppProxyController.php +++ b/lib/Controller/ExAppProxyController.php @@ -15,6 +15,7 @@ use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OCA\AppAPI\AppInfo\Application; use OCA\AppAPI\Db\ExApp; +use OCA\AppAPI\Db\ExAppMapper; use OCA\AppAPI\Db\ExAppRouteAccessLevel; use OCA\AppAPI\ProxyResponse; use OCA\AppAPI\Service\AppAPIService; @@ -261,9 +262,7 @@ private function prepareProxy( ); return null; } - $bruteforceProtection = isset($route['bruteforce_protection']) - ? json_decode($route['bruteforce_protection'], true) - : []; + $bruteforceProtection = ExAppMapper::parseJsonList($route['bruteforce_protection'] ?? null); if (!empty($bruteforceProtection)) { $delay = $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), Application::APP_ID); } @@ -350,8 +349,10 @@ private function passesExAppProxyRouteAccessLevelCheck(int $accessLevel): bool { } private function buildHeadersWithExclude(array $route, array $headers): array { - $headersToExclude = json_decode($route['headers_to_exclude'], true); - $headersToExclude = array_map('strtolower', $headersToExclude); + $headersToExclude = array_map( + 'strtolower', + array_filter(ExAppMapper::parseJsonList($route['headers_to_exclude'] ?? null), 'is_string') + ); if (!in_array('x-origin-ip', $headersToExclude)) { $headersToExclude[] = 'x-origin-ip'; diff --git a/lib/Db/ExAppMapper.php b/lib/Db/ExAppMapper.php index 21666220..a50ab1d0 100644 --- a/lib/Db/ExAppMapper.php +++ b/lib/Db/ExAppMapper.php @@ -25,6 +25,18 @@ public function __construct(IDBConnection $db) { parent::__construct($db, 'ex_apps'); } + /** + * Decode a JSON-list column (`bruteforce_protection`, `headers_to_exclude`) into an array, + * tolerating NULL / non-string / malformed values from legacy rows. + */ + public static function parseJsonList(mixed $raw): array { + if (!is_string($raw)) { + return []; + } + $decoded = json_decode($raw, true); + return is_array($decoded) ? $decoded : []; + } + /** * @throws Exception * diff --git a/lib/Service/ExAppService.php b/lib/Service/ExAppService.php index e9677589..0df28cb7 100644 --- a/lib/Service/ExAppService.php +++ b/lib/Service/ExAppService.php @@ -418,9 +418,8 @@ public function getExApps(): array { public function registerExAppRoutes(ExApp $exApp, array $routes): ?ExApp { try { $this->exAppMapper->registerExAppRoutes($exApp, $routes); - $exApp->setRoutes($routes); - return $exApp; - } catch (Exception $e) { + return $this->exAppMapper->findByAppId($exApp->getAppid()); + } catch (Exception|MultipleObjectsReturnedException|DoesNotExistException $e) { $this->logger->error(sprintf('Error while registering ExApp %s routes: %s. Routes: %s', $exApp->getAppid(), $e->getMessage(), json_encode($routes))); return null; } diff --git a/lib/Service/HarpService.php b/lib/Service/HarpService.php index 979fe44c..ca18b5ae 100644 --- a/lib/Service/HarpService.php +++ b/lib/Service/HarpService.php @@ -13,6 +13,7 @@ use GuzzleHttp\Exception\ClientException; use OCA\AppAPI\Db\DaemonConfig; use OCA\AppAPI\Db\ExApp; +use OCA\AppAPI\Db\ExAppMapper; use OCA\AppAPI\DeployActions\ManualActions; use OCP\ICertificateManager; use OCP\IConfig; @@ -116,14 +117,10 @@ public function getHarpExApp(ExApp $exApp): array { 'host' => $this->getExAppHost($exApp), 'port' => $exApp->getPort(), 'routes' => array_map(function ($route) { - $bruteforceList = json_decode($route['bruteforce_protection'], true); - if (!$bruteforceList) { - $bruteforceList = []; - } return [ 'url' => $route['url'], 'access_level' => $route['access_level'], - 'bruteforce_protection' => $bruteforceList, + 'bruteforce_protection' => ExAppMapper::parseJsonList($route['bruteforce_protection'] ?? null), ]; }, $exApp->getRoutes()), ];