From ec4e697904a546532527d9b4c9e83949f015ee03 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 3 Apr 2025 13:02:35 +0200 Subject: [PATCH] fix(apps): configuration to bypass checks for services Onlyoffice server sends requests directly to the nextcloud instance. Add configuration settings `allow_ip_ranges` and `allow_path_prefix` to allow these requests to bypass tos checks. Fixes #771. Signed-off-by: Max --- README.md | 17 +++++++++++++++++ lib/Checker.php | 46 ++++++++++++++++++++++++++++++---------------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3d5c0d8a..e80cf06c 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,23 @@ Default is enabled: `1` ./occ config:app:set terms_of_service tos_for_users --value '0' ``` +## 🔌 Allow access from other services + +Some other services such as office suites communicate directly with the Nextcloud server. +For Nextcloud Office and Officeonline the `wopi_allowlist` settings of the respective apps are taken into account. + +To allow other services to bypass the terms of service check: +* Set `allow_ip_ranges` to match the ip addresses of the servers in question. +* Set `allow_path_prefix` to the paths that access should be granted to. + +Default for `allow_ip_ranges` is none: `` +Default for `allow_path_prefix` is none: `` + +``` +./occ config:app:set terms_of_service allow_ip_range --value '10.0.0.5,10.0.0.6' +./occ config:app:set terms_of_service allow_path_prefix --value '/apps/onlyoffice/download' +``` + ## 🏗️ Development setup 1. Clone the repository diff --git a/lib/Checker.php b/lib/Checker.php index a377e55c..ac53d568 100644 --- a/lib/Checker.php +++ b/lib/Checker.php @@ -88,8 +88,8 @@ public function currentUserHasSigned(): bool { } } - if ($this->isValidWOPIRequest()) { - // Richdocuments and Collabora doing WOPI requests for the user + if ($this->isAllowedRequest()) { + // Services such as Collabora doing requests for the user return true; } @@ -126,27 +126,41 @@ public function currentUserHasSigned(): bool { return false; } - protected function isValidWOPIRequest(): bool { - return $this->isWOPIRemoteAddress() - && $this->isAllowedAppPath() + protected function isAllowedRequest(): bool { + return $this->isRequestAllowedInConfig() + || $this->isValidWOPIRequest('richdocuments') + || $this->isValidWOPIRequest('officeonline'); + } + + protected function isRequestAllowedInConfig(): bool { + $allowedPath = $this->config->getAppValue(Application::APPNAME, 'allow_path_prefix'); + $allowedRanges = $this->allowedRangeForApp(Application::APPNAME, 'allow_ip_ranges'); + return $this->isRemoteAddressInRanges($allowedRanges) + && $this->isPathInfoStartingWith($allowedPath) + && $this->isAllowedScriptName(); + } + + protected function isValidWOPIRequest(string $app): bool { + $allowedPath = '/apps/' . $app . '/wopi/'; + $allowedRanges = $this->allowedRangeForApp($app, 'wopi_allowlist'); + return $this->isRemoteAddressInRanges($allowedRanges) + && $this->isPathInfoStartingWith($allowedPath) && $this->isAllowedScriptName(); } - protected function isAllowedAppPath(): bool { - return strpos($this->request->getPathInfo(), '/apps/richdocuments/wopi/') === 0 - || strpos($this->request->getPathInfo(), '/apps/officeonline/wopi/') === 0; + protected function isPathInfoStartingWith(string $allowedPath): bool { + // no path allowed + if ($allowedPath === '') { + return false; + } + return strpos($this->request->getPathInfo(), $allowedPath) === 0; } protected function isAllowedScriptName(): bool { return substr($this->request->getScriptName(), 0 - strlen('/index.php')) === '/index.php'; } - protected function isWOPIRemoteAddress(): bool { - $allowedRanges = array_merge( - $this->allowedRangeForApp('richdocuments'), - $this->allowedRangeForApp('officeonline') - ); - + protected function isRemoteAddressInRanges(array $allowedRanges): bool { $userIp = $this->request->getRemoteAddress(); foreach ($allowedRanges as $range) { try { @@ -164,8 +178,8 @@ protected function isWOPIRemoteAddress(): bool { return false; } - private function allowedRangeForApp(string $appId): array { - $allowedRangesString = $this->config->getAppValue($appId, 'wopi_allowlist'); + private function allowedRangeForApp(string $appId, string $configKey): array { + $allowedRangesString = $this->config->getAppValue($appId, $configKey); if ($allowedRangesString === '') { return []; }