summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2023-05-26 17:58:44 +0200
committerJoas Schilling <coding@schilljs.com>2023-06-01 06:34:48 +0200
commit67c22f97d7d9a10fe085f7bc65ee4f0c23c9e652 (patch)
tree483c2e4470e4af917e1f19bc8cad5e0ba2448e3b /lib
parentf3ae7767765cad30ec28b8e8d45e2c1d65483f22 (diff)
feat(API): Allow to block older clients
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Middleware/CanUseTalkMiddleware.php101
-rw-r--r--lib/Middleware/Exceptions/UnsupportedClientVersionException.php40
2 files changed, 129 insertions, 12 deletions
diff --git a/lib/Middleware/CanUseTalkMiddleware.php b/lib/Middleware/CanUseTalkMiddleware.php
index f659cf952..b76132091 100644
--- a/lib/Middleware/CanUseTalkMiddleware.php
+++ b/lib/Middleware/CanUseTalkMiddleware.php
@@ -29,6 +29,7 @@ use OCA\Talk\Controller\SignalingController;
use OCA\Talk\Exceptions\ForbiddenException;
use OCA\Talk\Middleware\Attribute\RequireCallEnabled;
use OCA\Talk\Middleware\Exceptions\CanNotUseTalkException;
+use OCA\Talk\Middleware\Exceptions\UnsupportedClientVersionException;
use OCA\Talk\Room;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
@@ -39,31 +40,61 @@ use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCSController;
use OCP\IConfig;
use OCP\IGroupManager;
+use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
class CanUseTalkMiddleware extends Middleware {
- private IUserSession $userSession;
- private IGroupManager $groupManager;
- private Config $talkConfig;
- private IConfig $serverConfig;
+ /**
+ * Talk Desktop user agent but with a regex match for the version
+ * @see IRequest::USER_AGENT_TALK_DESKTOP
+ */
+ public const USER_AGENT_TALK_DESKTOP = '/^Mozilla\/5\.0 \((?!Android|iOS)[A-Za-z ]+\) Nextcloud-Talk v([^ ]*).*$/';
+ public const TALK_DESKTOP_MIN_VERSION = '0.6.0';
+
+ /**
+ * Talk Android user agent but with a regex match for the version
+ * @see IRequest::USER_AGENT_TALK_ANDROID
+ */
+ public const USER_AGENT_TALK_ANDROID = '/^Mozilla\/5\.0 \(Android\) Nextcloud\-Talk v([^ ]*).*$/';
+ public const TALK_ANDROID_MIN_VERSION = '15.0.0';
+
+ /**
+ * Talk iOS user agent but with a regex match for the version
+ * @see IRequest::USER_AGENT_TALK_IOS
+ */
+ public const USER_AGENT_TALK_IOS = '/^Mozilla\/5\.0 \(iOS\) Nextcloud\-Talk v([^ ]*).*$/';
+ public const TALK_IOS_MIN_VERSION = '15.0.0';
+
public function __construct(
- IUserSession $userSession,
- IGroupManager $groupManager,
- Config $talkConfig,
- IConfig $serverConfig,
+ protected IUserSession $userSession,
+ protected IGroupManager $groupManager,
+ protected Config $talkConfig,
+ protected IConfig $serverConfig,
+ protected IRequest $request,
) {
- $this->userSession = $userSession;
- $this->groupManager = $groupManager;
- $this->talkConfig = $talkConfig;
- $this->serverConfig = $serverConfig;
}
/**
* @throws CanNotUseTalkException
+ * @throws UnsupportedClientVersionException
*/
public function beforeController(Controller $controller, string $methodName): void {
+ if ($this->request->isUserAgent([
+ IRequest::USER_AGENT_TALK_DESKTOP,
+ IRequest::USER_AGENT_TALK_ANDROID,
+ IRequest::USER_AGENT_TALK_IOS,
+ ])) {
+ if ($this->request->isUserAgent([IRequest::USER_AGENT_TALK_DESKTOP])) {
+ $this->throwIfUnsupportedClientVersion('desktop', $this->request->getHeader('USER_AGENT'));
+ } elseif ($this->request->isUserAgent([IRequest::USER_AGENT_TALK_ANDROID])) {
+ $this->throwIfUnsupportedClientVersion('android', $this->request->getHeader('USER_AGENT'));
+ } elseif ($this->request->isUserAgent([IRequest::USER_AGENT_TALK_IOS])) {
+ $this->throwIfUnsupportedClientVersion('ios', $this->request->getHeader('USER_AGENT'));
+ }
+ }
+
$user = $this->userSession->getUser();
if ($user instanceof IUser && $this->talkConfig->isDisabledForUser($user)) {
if ($methodName === 'getWelcomeMessage'
@@ -93,6 +124,14 @@ class CanUseTalkMiddleware extends Middleware {
* @return Response
*/
public function afterException($controller, $methodName, \Exception $exception): Response {
+ if ($exception instanceof UnsupportedClientVersionException) {
+ if ($controller instanceof OCSController) {
+ throw new OCSException($exception->getMinVersion(), Http::STATUS_UPGRADE_REQUIRED);
+ }
+
+ return new RedirectToDefaultAppResponse();
+ }
+
if ($exception instanceof CanNotUseTalkException ||
$exception instanceof ForbiddenException) {
if ($controller instanceof OCSController) {
@@ -104,4 +143,42 @@ class CanUseTalkMiddleware extends Middleware {
throw $exception;
}
+
+ /**
+ * @param string $client
+ * @param string $userAgent
+ * @throws UnsupportedClientVersionException
+ */
+ protected function throwIfUnsupportedClientVersion(string $client, string $userAgent): void {
+ $configMinVersion = $this->serverConfig->getAppValue('spreed', 'minimum.supported.' . $client . '.version');
+
+ if ($client === 'desktop') {
+ $versionRegex = self::USER_AGENT_TALK_DESKTOP;
+ $minVersion = self::TALK_DESKTOP_MIN_VERSION;
+ } elseif ($client === 'android') {
+ $versionRegex = self::USER_AGENT_TALK_ANDROID;
+ $minVersion = self::TALK_ANDROID_MIN_VERSION;
+ } elseif ($client === 'ios') {
+ $versionRegex = self::USER_AGENT_TALK_IOS;
+ $minVersion = self::TALK_IOS_MIN_VERSION;
+ } else {
+ return;
+ }
+
+ preg_match($versionRegex, $userAgent, $matches);
+
+ if (isset($matches[1])) {
+ $clientVersion = $matches[1];
+
+ // API requirement and safety net
+ if (version_compare($clientVersion, $minVersion, '<')) {
+ throw new UnsupportedClientVersionException($minVersion);
+ }
+
+ // Admin option to be more pushy
+ if ($configMinVersion && version_compare($clientVersion, $configMinVersion, '<')) {
+ throw new UnsupportedClientVersionException($configMinVersion);
+ }
+ }
+ }
}
diff --git a/lib/Middleware/Exceptions/UnsupportedClientVersionException.php b/lib/Middleware/Exceptions/UnsupportedClientVersionException.php
new file mode 100644
index 000000000..474560123
--- /dev/null
+++ b/lib/Middleware/Exceptions/UnsupportedClientVersionException.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Talk\Middleware\Exceptions;
+
+use OCP\AppFramework\Http;
+
+class UnsupportedClientVersionException extends \Exception {
+ public function __construct(
+ protected string $version,
+ ) {
+ parent::__construct('Unsupported client version', Http::STATUS_UPGRADE_REQUIRED);
+ }
+
+ public function getMinVersion(): string {
+ return $this->version;
+ }
+}