Example #1
0
def get_client_name(request: HttpRequest, is_browser_view: bool) -> str:
    # If the API request specified a client in the request content,
    # that has priority.  Otherwise, extract the client from the
    # User-Agent.
    if 'client' in request.GET:
        return request.GET['client']
    if 'client' in request.POST:
        return request.POST['client']
    if "HTTP_USER_AGENT" in request.META:
        user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])  # type: Optional[Dict[str, str]]
    else:
        user_agent = None
    if user_agent is not None:
        # We could check for a browser's name being "Mozilla", but
        # e.g. Opera and MobileSafari don't set that, and it seems
        # more robust to just key off whether it was a browser view
        if is_browser_view and not user_agent["name"].startswith("Zulip"):
            # Avoid changing the client string for browsers, but let
            # the Zulip desktop and mobile apps be themselves.
            return "website"
        else:
            return user_agent["name"]
    else:
        # In the future, we will require setting USER_AGENT, but for
        # now we just want to tag these requests so we can review them
        # in logs and figure out the extent of the problem
        if is_browser_view:
            return "website"
        else:
            return "Unspecified"
Example #2
0
def get_client_name(request, is_json_view):
    # If the API request specified a client in the request content,
    # that has priority.  Otherwise, extract the client from the
    # User-Agent.
    if 'client' in request.REQUEST:
        return request.REQUEST['client']
    elif "HTTP_USER_AGENT" in request.META:
        user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])
        # We could check for a browser's name being "Mozilla", but
        # e.g. Opera and MobileSafari don't set that, and it seems
        # more robust to just key off whether it was a json view
        if user_agent["name"] != "ZulipDesktop" and is_json_view:
            # Avoid changing the client string for browsers Once this
            # is out to prod, we can name the field to something like
            # Browser for consistency.
            return "website"
        else:
            return user_agent["name"]
    else:
        # In the future, we will require setting USER_AGENT, but for
        # now we just want to tag these requests so we can review them
        # in logs and figure out the extent of the problem
        if is_json_view:
            return "website"
        else:
             return "Unspecified"
Example #3
0
def check_global_compatibility(request: HttpRequest) -> HttpResponse:
    if request.META.get('HTTP_USER_AGENT') is None:
        return json_error(_('User-Agent header missing from request'))

    # This string should not be tagged for translation, since old
    # clients are checking for an extra string.
    legacy_compatibility_error_message = "Client is too old"
    user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])
    if user_agent['name'] == "ZulipInvalid":
        return json_error(legacy_compatibility_error_message)
    if user_agent['name'] == "ZulipMobile":
        user_os = find_mobile_os(request.META["HTTP_USER_AGENT"])
        if (user_os == 'android'
                and version_lt(user_agent['version'], android_min_app_version)):
            return json_error(legacy_compatibility_error_message)
    return json_success()
Example #4
0
def get_client_name(request: HttpRequest) -> str:
    # If the API request specified a client in the request content,
    # that has priority.  Otherwise, extract the client from the
    # User-Agent.
    if 'client' in request.GET:  # nocoverage
        return request.GET['client']
    if 'client' in request.POST:
        return request.POST['client']
    if "HTTP_USER_AGENT" in request.META:
        user_agent: Optional[Dict[str, str]] = parse_user_agent(
            request.META["HTTP_USER_AGENT"])
    else:
        user_agent = None
    if user_agent is not None:
        return user_agent["name"]

    # In the future, we will require setting USER_AGENT, but for
    # now we just want to tag these requests so we can review them
    # in logs and figure out the extent of the problem
    return "Unspecified"
Example #5
0
    def test_user_agent_parsing(self):
        # type: () -> None
        """Test for our user agent parsing logic, using a large data set."""
        user_agents_parsed = defaultdict(int)  # type: Dict[str, int]
        user_agents_path = os.path.join(settings.DEPLOY_ROOT, "zerver/fixtures/user_agents_unique")
        parse_errors = []
        for line in open(user_agents_path).readlines():
            line = line.strip()
            match = re.match('^(?P<count>[0-9]+) "(?P<user_agent>.*)"$', line)
            self.assertIsNotNone(match)
            groupdict = match.groupdict()
            count = groupdict["count"]
            user_agent = groupdict["user_agent"]
            ret = parse_user_agent(user_agent)
            self.assertIsNotNone(ret)
            if ret is None:  # nocoverage
                parse_errors.append(line)
                continue
            user_agents_parsed[ret["name"]] += int(count)

        self.assertEqual(len(parse_errors), 0)
Example #6
0
    def test_user_agent_parsing(self):
        # type: () -> None
        """Test for our user agent parsing logic, using a large data set."""
        user_agents_parsed = defaultdict(int)  # type: Dict[str, int]
        user_agents_path = os.path.join(settings.DEPLOY_ROOT, "zerver/fixtures/user_agents_unique")
        parse_errors = []
        for line in open(user_agents_path).readlines():
            line = line.strip()
            match = re.match('^(?P<count>[0-9]+) "(?P<user_agent>.*)"$', line)
            self.assertIsNotNone(match)
            groupdict = match.groupdict()
            count = groupdict["count"]
            user_agent = groupdict["user_agent"]
            ret = parse_user_agent(user_agent)
            self.assertIsNotNone(ret)
            if ret is None:  # nocoverage
                parse_errors.append(line)
                continue
            user_agents_parsed[ret["name"]] += int(count)

        self.assertEqual(len(parse_errors), 0)
Example #7
0
def is_outdated_desktop_app(user_agent_str: str) -> Tuple[bool, bool, bool]:
    # 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.
        return (True, True, True)

    if user_agent['name'] != 'ZulipElectron':
        return (False, False, False)

    if version_lt(user_agent['version'], '4.0.0'):
        # Version 2.3.82 and older (aka <4.0.0) of the modern
        # Electron-based Zulip desktop app with known security issues.
        # won't auto-update; we may want a special notice to
        # distinguish those from modern releases.
        return (True, True, True)

    if version_lt(user_agent['version'], '4.0.3'):
        # Other insecure versions should just warn.
        return (True, False, False)

    return (False, False, False)
Example #8
0
def start_social_login(request: HttpRequest,
                       backend: str,
                       extra_arg: Optional[str] = None) -> HttpResponse:
    user_agent = parse_user_agent(
        request.META.get("HTTP_USER_AGENT", "Missing User-Agent"))
    if user_agent["name"] == "ZulipElectron":
        return render(request, "zerver/desktop_login.html")

    backend_url = reverse('social:begin', args=[backend])
    extra_url_params: Dict[str, str] = {}
    if backend == "saml":
        result = SAMLAuthBackend.check_config()
        if result is not None:
            return result

        # This backend requires the name of the IdP (from the list of configured ones)
        # to be passed as the parameter.
        if not extra_arg or extra_arg not in settings.SOCIAL_AUTH_SAML_ENABLED_IDPS:
            logging.info(
                "Attempted to initiate SAML authentication with wrong idp argument: %s",
                extra_arg)
            return redirect_to_config_error("saml")
        extra_url_params = {'idp': extra_arg}

    # TODO: Add AzureAD also.
    if backend in ["github", "google", "gitlab"]:
        key_setting = "SOCIAL_AUTH_" + backend.upper() + "_KEY"
        secret_setting = "SOCIAL_AUTH_" + backend.upper() + "_SECRET"
        if not (getattr(settings, key_setting)
                and getattr(settings, secret_setting)):
            return redirect_to_config_error(backend)

    return oauth_redirect_to_root(request,
                                  backend_url,
                                  'social',
                                  extra_url_params=extra_url_params)
Example #9
0
def check_compatibility(request: HttpRequest) -> HttpResponse:
    user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])
    if user_agent['name'] == "ZulipInvalid":
        return json_error("Client is too old")
    return json_success()
Example #10
0
def check_compatibility(request: HttpRequest) -> HttpResponse:
    user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])
    if user_agent is None or user_agent['name'] == "ZulipInvalid":
        return json_error("Client is too old")
    return json_success()
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from zerver.lib.user_agent import parse_user_agent

user_agents_parsed = defaultdict(int)  # type: Dict[str, int]
user_agents_path = os.path.join(os.path.dirname(__file__),
                                "user_agents_unique")
parse_errors = 0
for line in open(user_agents_path).readlines():
    line = line.strip()
    match = re.match('^(?P<count>[0-9]+) "(?P<user_agent>.*)"$', line)
    if match is None:
        print(line)
        continue
    groupdict = match.groupdict()
    count = groupdict["count"]
    user_agent = groupdict["user_agent"]
    ret = parse_user_agent(user_agent)
    if ret is None:
        print("parse error", line)
        parse_errors += 1
        continue
    user_agents_parsed[ret["name"]] += int(count)

for key in user_agents_parsed:
    print("    ", key, user_agents_parsed[key])

print("%s parse errors!" % (parse_errors, ))
Example #12
0
def check_server_incompatibility(request: HttpRequest) -> bool:
    user_agent = parse_user_agent(request.META.get("HTTP_USER_AGENT", "Missing User-Agent"))
    return user_agent['name'] == "ZulipInvalid"
Example #13
0
def check_server_incompatibility(request: HttpRequest) -> bool:
    user_agent = parse_user_agent(
        request.headers.get("User-Agent", "Missing User-Agent"))
    return user_agent["name"] == "ZulipInvalid"
Example #14
0
    def wrapper(request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse:
        user_agent = parse_user_agent(request.META.get("HTTP_USER_AGENT", "Missing User-Agent"))
        if user_agent["name"] == "ZulipElectron":
            return render(request, "zerver/desktop_login.html")

        return func(request, *args, **kwargs)
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from zerver.lib.user_agent import parse_user_agent

user_agents_parsed = defaultdict(int) # type: Dict[str, int]
user_agents_path = os.path.join(os.path.dirname(__file__), "user_agents_unique")
parse_errors = 0
for line in open(user_agents_path).readlines():
    line = line.strip()
    match = re.match('^(?P<count>[0-9]+) "(?P<user_agent>.*)"$', line)
    if match is None:
        print(line)
        continue
    groupdict = match.groupdict()
    count = groupdict["count"]
    user_agent = groupdict["user_agent"]
    ret = parse_user_agent(user_agent)
    if ret is None:
        print("parse error", line)
        parse_errors += 1
        continue
    user_agents_parsed[ret["name"]] += int(count)

for key in user_agents_parsed:
    print("    ", key, user_agents_parsed[key])

print("%s parse errors!" % (parse_errors,))
Example #16
0
def check_server_incompatibility(request: HttpRequest) -> bool:
    user_agent = parse_user_agent(request.META.get("HTTP_USER_AGENT", "Missing User-Agent"))
    return user_agent["name"] == "ZulipInvalid"
Example #17
0
File: auth.py Project: sims34/zulip
def check_server_incompatibility(request: HttpRequest) -> bool:
    user_agent = parse_user_agent(request.META["HTTP_USER_AGENT"])
    return user_agent['name'] == "ZulipInvalid"