diff --git a/zerver/lib/users.py b/zerver/lib/users.py index aac6791787..7718fdc7b8 100644 --- a/zerver/lib/users.py +++ b/zerver/lib/users.py @@ -3,6 +3,7 @@ import unicodedata from collections import defaultdict from typing import Any, Dict, List, Optional, Sequence, Union, cast +import dateutil.parser as date_parser from django.conf import settings from django.core.exceptions import ValidationError from django.db.models.query import QuerySet @@ -425,6 +426,14 @@ def format_user_row( date_joined=row["date_joined"].isoformat(), ) + if acting_user is None: + # Remove data about other users which are not useful to spectators + # or can reveal personal information about a user. + # Only send day level precision date_joined data to spectators. + del result["is_billing_admin"] + del result["timezone"] + result["date_joined"] = str(date_parser.parse(result["date_joined"]).date()) + # Zulip clients that support using `GET /avatar/{user_id}` as a # fallback if we didn't send an avatar URL in the user object pass # user_avatar_url_field_optional in client_capabilities. diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py index 56d5567d76..141ff64e1f 100644 --- a/zerver/tests/test_home.py +++ b/zerver/tests/test_home.py @@ -360,6 +360,27 @@ class HomeTest(ZulipTestCase): self.assertEqual(actual_keys, expected_keys) self.assertEqual(self.client.session.get("prefers_web_public_view"), True) + # Test information passed to client about users. + page_params = self._get_page_params(result) + self.assertEqual( + sorted(page_params["realm_users"][0].keys()), + [ + "avatar_url", + "avatar_version", + "date_joined", + "email", + "full_name", + "is_admin", + "is_bot", + "is_guest", + "is_owner", + "role", + "user_id", + ], + ) + date_length = len("YYYY-MM-DD") + self.assert_length(page_params["realm_users"][0]["date_joined"], date_length) + # Web-public session key should clear once user is logged in self.login("hamlet") self.client_get("/")