diff --git a/version.py b/version.py index 537946f336..32d797ef66 100644 --- a/version.py +++ b/version.py @@ -13,6 +13,13 @@ LATEST_MAJOR_VERSION = "2.1" LATEST_RELEASE_VERSION = "2.1.2" LATEST_RELEASE_ANNOUNCEMENT = "https://blog.zulip.org/2019/12/13/zulip-2-1-released/" +# Versions of the desktop app below DESKTOP_MINIMUM_VERSION will be +# prevented from connecting to the Zulip server. Versions above +# DESKTOP_MINIMUM_VERSION but below DESKTOP_WARNING_VERSION will have +# a banner at the top of the page asking the user to upgrade. +DESKTOP_MINIMUM_VERSION = "5.0.0" +DESKTOP_WARNING_VERSION = "5.0.0" + # Bump the minor PROVISION_VERSION to indicate that folks should provision # only when going from an old version of the code to a newer version. Bump # the major version to indicate that folks should provision in both diff --git a/zerver/tests/test_compatibility.py b/zerver/tests/test_compatibility.py index 494f825e01..458ccf40e1 100644 --- a/zerver/tests/test_compatibility.py +++ b/zerver/tests/test_compatibility.py @@ -1,3 +1,5 @@ +import mock + from zerver.lib.test_classes import ZulipTestCase from zerver.views.compatibility import find_mobile_os, version_lt, is_outdated_desktop_app @@ -96,8 +98,15 @@ class CompatibilityTest(ZulipTestCase): def test_insecure_desktop_app(self) -> None: self.assertEqual(is_outdated_desktop_app('ZulipDesktop/0.5.2 (Mac)'), (True, True, True)) self.assertEqual(is_outdated_desktop_app('ZulipElectron/2.3.82 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/2.3.82 Chrome/61.0.3163.100 Electron/2.0.9 Safari/537.36'), (True, True, True)) - self.assertEqual(is_outdated_desktop_app('ZulipElectron/4.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36'), (True, False, False)) - self.assertEqual(is_outdated_desktop_app('ZulipElectron/4.0.3 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36'), (False, False, False)) + self.assertEqual(is_outdated_desktop_app('ZulipElectron/4.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36'), (True, True, False)) + + self.assertEqual(is_outdated_desktop_app('ZulipElectron/4.0.3 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36'), (True, True, False)) + + # Verify what happens if DESKTOP_MINIMUM_VERSION < v < DESKTOP_WARNING_VERSION + with mock.patch('zerver.views.compatibility.DESKTOP_MINIMUM_VERSION', '4.0.3'): + self.assertEqual(is_outdated_desktop_app('ZulipElectron/4.0.3 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36'), (True, False, False)) + + self.assertEqual(is_outdated_desktop_app('ZulipElectron/5.0.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36'), (False, False, False)) self.assertEqual(is_outdated_desktop_app('Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'), (False, False, False)) diff --git a/zerver/views/compatibility.py b/zerver/views/compatibility.py index f54b60546c..368f6822de 100644 --- a/zerver/views/compatibility.py +++ b/zerver/views/compatibility.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext as _ from zerver.lib.response import json_error, json_success from zerver.lib.user_agent import parse_user_agent +from version import DESKTOP_MINIMUM_VERSION, DESKTOP_WARNING_VERSION def pop_numerals(ver: str) -> Tuple[List[int], str]: match = re.search(r'^( \d+ (?: \. \d+ )* ) (.*)', ver, re.X) @@ -89,7 +90,7 @@ def check_global_compatibility(request: HttpRequest) -> HttpResponse: return json_success() def is_outdated_desktop_app(user_agent_str: str) -> Tuple[bool, bool, bool]: - # Returns (insecure, banned, auto_update_broken + # Returns (insecure, banned, auto_update_broken) user_agent = parse_user_agent(user_agent_str) if user_agent['name'] == 'ZulipDesktop': # The deprecated QT/webkit based desktop app, last updated in ~2016. @@ -105,7 +106,11 @@ def is_outdated_desktop_app(user_agent_str: str) -> Tuple[bool, bool, bool]: # distinguish those from modern releases. return (True, True, True) - if version_lt(user_agent['version'], '4.0.3'): + if version_lt(user_agent['version'], DESKTOP_MINIMUM_VERSION): + # Below DESKTOP_MINIMUM_VERSION, we reject access as well. + return (True, True, False) + + if version_lt(user_agent['version'], DESKTOP_WARNING_VERSION): # Other insecure versions should just warn. return (True, False, False)