mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
ruff: Fix UP007 Use X | Y
for type annotations.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
committed by
Tim Abbott
parent
e08a24e47f
commit
531b34cb4c
@@ -17,7 +17,7 @@ import json
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from email.headerregistry import Address
|
||||
from typing import Any, Callable, Optional, TypedDict, TypeVar, Union, cast
|
||||
from typing import Any, Callable, TypedDict, TypeVar, cast
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import magic
|
||||
@@ -153,8 +153,8 @@ def pad_method_dict(method_dict: dict[str, bool]) -> dict[str, bool]:
|
||||
|
||||
def auth_enabled_helper(
|
||||
backends_to_check: list[str],
|
||||
realm: Optional[Realm],
|
||||
realm_authentication_methods: Optional[dict[str, bool]] = None,
|
||||
realm: Realm | None,
|
||||
realm_authentication_methods: dict[str, bool] | None = None,
|
||||
) -> bool:
|
||||
"""
|
||||
realm_authentication_methods can be passed if already fetched to avoid
|
||||
@@ -179,19 +179,19 @@ def auth_enabled_helper(
|
||||
|
||||
|
||||
def ldap_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["LDAP"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def email_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["Email"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def password_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return ldap_auth_enabled(realm, realm_authentication_methods) or email_auth_enabled(
|
||||
realm, realm_authentication_methods
|
||||
@@ -199,48 +199,48 @@ def password_auth_enabled(
|
||||
|
||||
|
||||
def dev_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["Dev"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def google_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["Google"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def github_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["GitHub"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def gitlab_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["GitLab"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def apple_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["Apple"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def saml_auth_enabled(
|
||||
realm: Optional[Realm] = None, realm_authentication_methods: Optional[dict[str, bool]] = None
|
||||
realm: Realm | None = None, realm_authentication_methods: dict[str, bool] | None = None
|
||||
) -> bool:
|
||||
return auth_enabled_helper(["SAML"], realm, realm_authentication_methods)
|
||||
|
||||
|
||||
def require_email_format_usernames(realm: Optional[Realm] = None) -> bool:
|
||||
def require_email_format_usernames(realm: Realm | None = None) -> bool:
|
||||
if ldap_auth_enabled(realm) and (settings.LDAP_EMAIL_ATTR or settings.LDAP_APPEND_DOMAIN):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_user_active(user_profile: UserProfile, return_data: Optional[dict[str, Any]] = None) -> bool:
|
||||
def is_user_active(user_profile: UserProfile, return_data: dict[str, Any] | None = None) -> bool:
|
||||
if user_profile.realm.deactivated:
|
||||
if return_data is not None:
|
||||
return_data["inactive_realm"] = True
|
||||
@@ -258,8 +258,8 @@ def is_user_active(user_profile: UserProfile, return_data: Optional[dict[str, An
|
||||
|
||||
|
||||
def common_get_active_user(
|
||||
email: str, realm: Realm, return_data: Optional[dict[str, Any]] = None
|
||||
) -> Optional[UserProfile]:
|
||||
email: str, realm: Realm, return_data: dict[str, Any] | None = None
|
||||
) -> UserProfile | None:
|
||||
"""This is the core common function used by essentially all
|
||||
authentication backends to check if there's an active user account
|
||||
with a given email address in the organization, handling both
|
||||
@@ -305,7 +305,7 @@ def is_subdomain_in_allowed_subdomains_list(subdomain: str, allowed_subdomains:
|
||||
return False
|
||||
|
||||
|
||||
AuthFuncT = TypeVar("AuthFuncT", bound=Callable[..., Optional[UserProfile]])
|
||||
AuthFuncT = TypeVar("AuthFuncT", bound=Callable[..., UserProfile | None])
|
||||
|
||||
|
||||
class RateLimitedAuthenticationByUsername(RateLimitedObject):
|
||||
@@ -340,7 +340,7 @@ def auth_rate_limiting_already_applied(request: HttpRequest) -> bool:
|
||||
# @decorator does this for us.
|
||||
# The usual @wraps from functools breaks signatures, so it can't be used here.
|
||||
@decorator
|
||||
def custom_auth_decorator(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> Optional[UserProfile]:
|
||||
def custom_auth_decorator(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> UserProfile | None:
|
||||
custom_auth_wrapper_func = settings.CUSTOM_AUTHENTICATION_WRAPPER_FUNCTION
|
||||
if custom_auth_wrapper_func is None:
|
||||
return auth_func(*args, **kwargs)
|
||||
@@ -349,7 +349,7 @@ def custom_auth_decorator(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> Op
|
||||
|
||||
|
||||
@decorator
|
||||
def rate_limit_auth(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> Optional[UserProfile]:
|
||||
def rate_limit_auth(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> UserProfile | None:
|
||||
if not settings.RATE_LIMITING_AUTHENTICATE:
|
||||
return auth_func(*args, **kwargs)
|
||||
|
||||
@@ -379,7 +379,7 @@ def rate_limit_auth(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> Optional
|
||||
|
||||
|
||||
@decorator
|
||||
def log_auth_attempts(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> Optional[UserProfile]:
|
||||
def log_auth_attempts(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> UserProfile | None:
|
||||
result = auth_func(*args, **kwargs)
|
||||
|
||||
backend_instance = args[0]
|
||||
@@ -428,12 +428,12 @@ class ZulipAuthMixin:
|
||||
"""
|
||||
|
||||
name = "undefined"
|
||||
_logger: Optional[logging.Logger] = None
|
||||
_logger: logging.Logger | None = None
|
||||
|
||||
# Describes which plans gives access to this authentication method on zulipchat.com.
|
||||
# None means the backend is available regardless of the plan.
|
||||
# Otherwise, it should be a list of Realm.plan_type values that give access to the backend.
|
||||
available_for_cloud_plans: Optional[list[int]] = None
|
||||
available_for_cloud_plans: list[int] | None = None
|
||||
|
||||
@property
|
||||
def logger(self) -> logging.Logger:
|
||||
@@ -441,7 +441,7 @@ class ZulipAuthMixin:
|
||||
self._logger = logging.getLogger(f"zulip.auth.{self.name}")
|
||||
return self._logger
|
||||
|
||||
def get_user(self, user_profile_id: int) -> Optional[UserProfile]:
|
||||
def get_user(self, user_profile_id: int) -> UserProfile | None:
|
||||
"""Override the Django method for getting a UserProfile object from
|
||||
the user_profile_id,."""
|
||||
try:
|
||||
@@ -464,13 +464,13 @@ class ZulipDummyBackend(ZulipAuthMixin):
|
||||
@custom_auth_decorator
|
||||
def authenticate(
|
||||
self,
|
||||
request: Optional[HttpRequest] = None,
|
||||
request: HttpRequest | None = None,
|
||||
*,
|
||||
username: str,
|
||||
realm: Realm,
|
||||
use_dummy_backend: bool = False,
|
||||
return_data: Optional[dict[str, Any]] = None,
|
||||
) -> Optional[UserProfile]:
|
||||
return_data: dict[str, Any] | None = None,
|
||||
) -> UserProfile | None:
|
||||
if use_dummy_backend:
|
||||
return common_get_active_user(username, realm, return_data)
|
||||
return None
|
||||
@@ -514,8 +514,8 @@ class EmailAuthBackend(ZulipAuthMixin):
|
||||
username: str,
|
||||
password: str,
|
||||
realm: Realm,
|
||||
return_data: Optional[dict[str, Any]] = None,
|
||||
) -> Optional[UserProfile]:
|
||||
return_data: dict[str, Any] | None = None,
|
||||
) -> UserProfile | None:
|
||||
"""Authenticate a user based on email address as the user name."""
|
||||
if not password_auth_enabled(realm):
|
||||
if return_data is not None:
|
||||
@@ -706,16 +706,16 @@ class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend):
|
||||
# Disable django-auth-ldap's permissions functions -- we don't use
|
||||
# the standard Django user/group permissions system because they
|
||||
# are prone to performance issues.
|
||||
def has_perm(self, user: Optional[UserProfile], perm: Any, obj: Any = None) -> bool:
|
||||
def has_perm(self, user: UserProfile | None, perm: Any, obj: Any = None) -> bool:
|
||||
return False
|
||||
|
||||
def has_module_perms(self, user: Optional[UserProfile], app_label: Optional[str]) -> bool:
|
||||
def has_module_perms(self, user: UserProfile | None, app_label: str | None) -> bool:
|
||||
return False
|
||||
|
||||
def get_all_permissions(self, user: Optional[UserProfile], obj: Any = None) -> set[Any]:
|
||||
def get_all_permissions(self, user: UserProfile | None, obj: Any = None) -> set[Any]:
|
||||
return set()
|
||||
|
||||
def get_group_permissions(self, user: Optional[UserProfile], obj: Any = None) -> set[Any]:
|
||||
def get_group_permissions(self, user: UserProfile | None, obj: Any = None) -> set[Any]:
|
||||
return set()
|
||||
|
||||
def django_to_ldap_username(self, username: str) -> str:
|
||||
@@ -929,7 +929,7 @@ class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend):
|
||||
def sync_custom_profile_fields_from_ldap(
|
||||
self, user_profile: UserProfile, ldap_user: _LDAPUser
|
||||
) -> None:
|
||||
values_by_var_name: dict[str, Union[int, str, list[int]]] = {}
|
||||
values_by_var_name: dict[str, int | str | list[int]] = {}
|
||||
for attr, ldap_attr in settings.AUTH_LDAP_USER_ATTR_MAP.items():
|
||||
if not attr.startswith("custom_profile_field__"):
|
||||
continue
|
||||
@@ -1029,15 +1029,15 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
|
||||
@custom_auth_decorator
|
||||
def authenticate(
|
||||
self,
|
||||
request: Optional[HttpRequest] = None,
|
||||
request: HttpRequest | None = None,
|
||||
*,
|
||||
username: str,
|
||||
password: str,
|
||||
realm: Realm,
|
||||
prereg_realm: Optional[PreregistrationRealm] = None,
|
||||
prereg_user: Optional[PreregistrationUser] = None,
|
||||
return_data: Optional[dict[str, Any]] = None,
|
||||
) -> Optional[UserProfile]:
|
||||
prereg_realm: PreregistrationRealm | None = None,
|
||||
prereg_user: PreregistrationUser | None = None,
|
||||
return_data: dict[str, Any] | None = None,
|
||||
) -> UserProfile | None:
|
||||
self._realm = realm
|
||||
self._prereg_user = prereg_user
|
||||
self._prereg_realm = prereg_realm
|
||||
@@ -1204,13 +1204,13 @@ class ZulipLDAPUserPopulator(ZulipLDAPAuthBackendBase):
|
||||
|
||||
def authenticate(
|
||||
self,
|
||||
request: Optional[HttpRequest] = None,
|
||||
request: HttpRequest | None = None,
|
||||
*,
|
||||
username: str,
|
||||
password: str,
|
||||
realm: Realm,
|
||||
return_data: Optional[dict[str, Any]] = None,
|
||||
) -> Optional[UserProfile]:
|
||||
return_data: dict[str, Any] | None = None,
|
||||
) -> UserProfile | None:
|
||||
return None
|
||||
|
||||
def get_or_build_user(
|
||||
@@ -1348,12 +1348,12 @@ class DevAuthBackend(ZulipAuthMixin):
|
||||
|
||||
def authenticate(
|
||||
self,
|
||||
request: Optional[HttpRequest] = None,
|
||||
request: HttpRequest | None = None,
|
||||
*,
|
||||
dev_auth_username: str,
|
||||
realm: Realm,
|
||||
return_data: Optional[dict[str, Any]] = None,
|
||||
) -> Optional[UserProfile]:
|
||||
return_data: dict[str, Any] | None = None,
|
||||
) -> UserProfile | None:
|
||||
if not dev_auth_enabled(realm):
|
||||
return None
|
||||
return common_get_active_user(dev_auth_username, realm, return_data=return_data)
|
||||
@@ -1362,7 +1362,7 @@ class DevAuthBackend(ZulipAuthMixin):
|
||||
class ExternalAuthMethodDictT(TypedDict):
|
||||
name: str
|
||||
display_name: str
|
||||
display_icon: Optional[str]
|
||||
display_icon: str | None
|
||||
login_url: str
|
||||
signup_url: str
|
||||
|
||||
@@ -1377,7 +1377,7 @@ class ExternalAuthMethod(ABC):
|
||||
|
||||
auth_backend_name = "undeclared"
|
||||
name = "undeclared"
|
||||
display_icon: Optional[str] = None
|
||||
display_icon: str | None = None
|
||||
|
||||
# Used to determine how to order buttons on login form, backend with
|
||||
# higher sort order are displayed first.
|
||||
@@ -1385,7 +1385,7 @@ class ExternalAuthMethod(ABC):
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def dict_representation(cls, realm: Optional[Realm] = None) -> list[ExternalAuthMethodDictT]:
|
||||
def dict_representation(cls, realm: Realm | None = None) -> list[ExternalAuthMethodDictT]:
|
||||
"""
|
||||
Method returning dictionaries representing the authentication methods
|
||||
corresponding to the backend that subclasses this. The documentation
|
||||
@@ -1415,8 +1415,8 @@ class ExternalAuthDataDict(TypedDict, total=False):
|
||||
is_signup: bool
|
||||
is_realm_creation: bool
|
||||
redirect_to: str
|
||||
mobile_flow_otp: Optional[str]
|
||||
desktop_flow_otp: Optional[str]
|
||||
mobile_flow_otp: str | None
|
||||
desktop_flow_otp: str | None
|
||||
multiuse_object_key: str
|
||||
full_name_validated: bool
|
||||
# The mobile app doesn't actually use a session, so this
|
||||
@@ -1433,10 +1433,10 @@ class ExternalAuthResult:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
user_profile: Optional[UserProfile] = None,
|
||||
data_dict: Optional[ExternalAuthDataDict] = None,
|
||||
request: Optional[HttpRequest] = None,
|
||||
login_token: Optional[str] = None,
|
||||
user_profile: UserProfile | None = None,
|
||||
data_dict: ExternalAuthDataDict | None = None,
|
||||
request: HttpRequest | None = None,
|
||||
login_token: str | None = None,
|
||||
delete_stored_data: bool = True,
|
||||
) -> None:
|
||||
if data_dict is None:
|
||||
@@ -1580,12 +1580,12 @@ class ZulipRemoteUserBackend(ZulipAuthMixin, RemoteUserBackend, ExternalAuthMeth
|
||||
@override
|
||||
def authenticate( # type: ignore[override] # authenticate has an incompatible signature with ModelBackend and BaseBackend
|
||||
self,
|
||||
request: Optional[HttpRequest] = None,
|
||||
request: HttpRequest | None = None,
|
||||
*,
|
||||
remote_user: str,
|
||||
realm: Realm,
|
||||
return_data: Optional[dict[str, Any]] = None,
|
||||
) -> Optional[UserProfile]:
|
||||
return_data: dict[str, Any] | None = None,
|
||||
) -> UserProfile | None:
|
||||
if not auth_enabled_helper(["RemoteUser"], realm):
|
||||
return None
|
||||
|
||||
@@ -1594,7 +1594,7 @@ class ZulipRemoteUserBackend(ZulipAuthMixin, RemoteUserBackend, ExternalAuthMeth
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
def dict_representation(cls, realm: Optional[Realm] = None) -> list[ExternalAuthMethodDictT]:
|
||||
def dict_representation(cls, realm: Realm | None = None) -> list[ExternalAuthMethodDictT]:
|
||||
return [
|
||||
dict(
|
||||
name=cls.name,
|
||||
@@ -1631,7 +1631,7 @@ def redirect_deactivated_user_to_login(realm: Realm, email: str) -> HttpResponse
|
||||
|
||||
def social_associate_user_helper(
|
||||
backend: BaseAuth, return_data: dict[str, Any], *args: Any, **kwargs: Any
|
||||
) -> Union[HttpResponse, Optional[UserProfile]]:
|
||||
) -> HttpResponse | UserProfile | None:
|
||||
"""Responsible for doing the Zulip account lookup and validation parts
|
||||
of the Zulip social auth pipeline (similar to the authenticate()
|
||||
methods in most other auth backends in this file).
|
||||
@@ -1783,7 +1783,7 @@ def social_associate_user_helper(
|
||||
@partial
|
||||
def social_auth_associate_user(
|
||||
backend: BaseAuth, *args: Any, **kwargs: Any
|
||||
) -> Union[HttpResponse, dict[str, Any]]:
|
||||
) -> HttpResponse | dict[str, Any]:
|
||||
"""A simple wrapper function to reformat the return data from
|
||||
social_associate_user_helper as a dictionary. The
|
||||
python-social-auth infrastructure will then pass those values into
|
||||
@@ -1807,7 +1807,7 @@ def social_auth_associate_user(
|
||||
|
||||
def social_auth_finish(
|
||||
backend: Any, details: dict[str, Any], response: HttpResponse, *args: Any, **kwargs: Any
|
||||
) -> Optional[HttpResponse]:
|
||||
) -> HttpResponse | None:
|
||||
"""Given the determination in social_auth_associate_user for whether
|
||||
the user should be authenticated, this takes care of actually
|
||||
logging in the user (if appropriate) and redirecting the browser
|
||||
@@ -2013,7 +2013,7 @@ class SocialAuthMixin(ZulipAuthMixin, ExternalAuthMethod, BaseAuth):
|
||||
|
||||
standard_relay_params = [*settings.SOCIAL_AUTH_FIELDS_STORED_IN_SESSION, "next"]
|
||||
|
||||
def auth_complete(self, *args: Any, **kwargs: Any) -> Optional[HttpResponse]:
|
||||
def auth_complete(self, *args: Any, **kwargs: Any) -> HttpResponse | None:
|
||||
"""This is a small wrapper around the core `auth_complete` method of
|
||||
python-social-auth, designed primarily to prevent 500s for
|
||||
exceptions in the social auth code from situations that are
|
||||
@@ -2049,7 +2049,7 @@ class SocialAuthMixin(ZulipAuthMixin, ExternalAuthMethod, BaseAuth):
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
def dict_representation(cls, realm: Optional[Realm] = None) -> list[ExternalAuthMethodDictT]:
|
||||
def dict_representation(cls, realm: Realm | None = None) -> list[ExternalAuthMethodDictT]:
|
||||
return [
|
||||
dict(
|
||||
name=cls.name,
|
||||
@@ -2286,7 +2286,7 @@ class AppleAuthBackend(SocialAuthMixin, AppleIdAuth):
|
||||
)
|
||||
return state
|
||||
|
||||
def validate_state(self) -> Optional[str]:
|
||||
def validate_state(self) -> str | None:
|
||||
"""
|
||||
This method replaces a method from python-social-auth; it is
|
||||
adapted to retrieve the data stored in Redis, save it in
|
||||
@@ -2337,7 +2337,7 @@ class AppleAuthBackend(SocialAuthMixin, AppleIdAuth):
|
||||
return user_details
|
||||
|
||||
@override
|
||||
def auth_complete(self, *args: Any, **kwargs: Any) -> Optional[HttpResponse]:
|
||||
def auth_complete(self, *args: Any, **kwargs: Any) -> HttpResponse | None:
|
||||
if not self.is_native_flow():
|
||||
# The default implementation in python-social-auth is the browser flow.
|
||||
return super().auth_complete(*args, **kwargs)
|
||||
@@ -2428,7 +2428,7 @@ class SAMLDocument:
|
||||
self.encoded_saml_message = encoded_saml_message
|
||||
self.backend = backend
|
||||
|
||||
self._decoded_saml_message: Optional[str] = None
|
||||
self._decoded_saml_message: str | None = None
|
||||
|
||||
@property
|
||||
def logger(self) -> logging.Logger:
|
||||
@@ -2457,7 +2457,7 @@ class SAMLDocument:
|
||||
"""
|
||||
return type(self).__name__
|
||||
|
||||
def get_issuing_idp(self) -> Optional[str]:
|
||||
def get_issuing_idp(self) -> str | None:
|
||||
"""
|
||||
Given a SAMLResponse or SAMLRequest, returns which of the configured IdPs
|
||||
is declared as the issuer.
|
||||
@@ -2523,7 +2523,7 @@ class SAMLResponse(SAMLDocument):
|
||||
self.logger.error("Error parsing SAMLResponse: %s", str(e))
|
||||
return []
|
||||
|
||||
def get_session_index(self) -> Optional[str]:
|
||||
def get_session_index(self) -> str | None:
|
||||
"""
|
||||
Returns the SessionIndex from the SAMLResponse.
|
||||
"""
|
||||
@@ -2637,7 +2637,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_data_from_redis(cls, key: str) -> Optional[dict[str, Any]]:
|
||||
def get_data_from_redis(cls, key: str) -> dict[str, Any] | None:
|
||||
data = None
|
||||
if key.startswith("saml_token_"):
|
||||
# Safety if statement, to not allow someone to poke around arbitrary Redis keys here.
|
||||
@@ -2664,7 +2664,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
|
||||
except orjson.JSONDecodeError:
|
||||
return {}
|
||||
|
||||
def choose_subdomain(self, relayed_params: dict[str, Any]) -> Optional[str]:
|
||||
def choose_subdomain(self, relayed_params: dict[str, Any]) -> str | None:
|
||||
subdomain = relayed_params.get("subdomain")
|
||||
if subdomain is not None:
|
||||
return subdomain
|
||||
@@ -2707,7 +2707,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
|
||||
return
|
||||
|
||||
subdomain = self.strategy.session_get("subdomain")
|
||||
entitlements: Union[str, list[str]] = attributes.get(org_membership_attribute, [])
|
||||
entitlements: str | list[str] = attributes.get(org_membership_attribute, [])
|
||||
if isinstance(entitlements, str): # nocoverage
|
||||
# This shouldn't happen as we'd always expect a list from this attribute even
|
||||
# if it only has one element, but it's safer to have this defensive code.
|
||||
@@ -2725,7 +2725,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
|
||||
)
|
||||
raise AuthFailed(self, error_msg)
|
||||
|
||||
def process_logout(self, subdomain: str, idp_name: str) -> Optional[HttpResponse]:
|
||||
def process_logout(self, subdomain: str, idp_name: str) -> HttpResponse | None:
|
||||
"""
|
||||
We override process_logout, because we need to customize
|
||||
the way of revoking sessions and introduce NameID validation.
|
||||
@@ -2797,7 +2797,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@override
|
||||
def auth_complete(self, *args: Any, **kwargs: Any) -> Optional[HttpResponse]:
|
||||
def auth_complete(self, *args: Any, **kwargs: Any) -> HttpResponse | None:
|
||||
"""
|
||||
Additional ugly wrapping on top of auth_complete in SocialAuthMixin.
|
||||
We handle two things for processing SAMLResponses here:
|
||||
@@ -2948,7 +2948,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
def dict_representation(cls, realm: Optional[Realm] = None) -> list[ExternalAuthMethodDictT]:
|
||||
def dict_representation(cls, realm: Realm | None = None) -> list[ExternalAuthMethodDictT]:
|
||||
result: list[ExternalAuthMethodDictT] = []
|
||||
for idp_name, idp_dict in settings.SOCIAL_AUTH_SAML_ENABLED_IDPS.items():
|
||||
if realm and not cls.validate_idp_for_subdomain(idp_name, realm.subdomain):
|
||||
@@ -3019,7 +3019,7 @@ class GenericOpenIdConnectBackend(SocialAuthMixin, OpenIdConnectAuth):
|
||||
settings_dict: OIDCIdPConfigDict
|
||||
[settings_dict] = settings.SOCIAL_AUTH_OIDC_ENABLED_IDPS.values() or [OIDCIdPConfigDict()]
|
||||
|
||||
display_icon: Optional[str] = settings_dict.get("display_icon", None)
|
||||
display_icon: str | None = settings_dict.get("display_icon", None)
|
||||
display_name: str = settings_dict.get("display_name", "OIDC")
|
||||
|
||||
full_name_validated = getattr(settings, "SOCIAL_AUTH_OIDC_FULL_NAME_VALIDATED", False)
|
||||
@@ -3050,7 +3050,7 @@ class GenericOpenIdConnectBackend(SocialAuthMixin, OpenIdConnectAuth):
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
def dict_representation(cls, realm: Optional[Realm] = None) -> list[ExternalAuthMethodDictT]:
|
||||
def dict_representation(cls, realm: Realm | None = None) -> list[ExternalAuthMethodDictT]:
|
||||
return [
|
||||
dict(
|
||||
name=f"oidc:{cls.name}",
|
||||
@@ -3069,7 +3069,7 @@ class GenericOpenIdConnectBackend(SocialAuthMixin, OpenIdConnectAuth):
|
||||
|
||||
|
||||
def validate_otp_params(
|
||||
mobile_flow_otp: Optional[str] = None, desktop_flow_otp: Optional[str] = None
|
||||
mobile_flow_otp: str | None = None, desktop_flow_otp: str | None = None
|
||||
) -> None:
|
||||
for otp in [mobile_flow_otp, desktop_flow_otp]:
|
||||
if otp is not None and not is_valid_otp(otp):
|
||||
@@ -3081,7 +3081,7 @@ def validate_otp_params(
|
||||
|
||||
class SAMLSPInitiatedLogout:
|
||||
@classmethod
|
||||
def get_logged_in_user_idp(cls, request: HttpRequest) -> Optional[str]:
|
||||
def get_logged_in_user_idp(cls, request: HttpRequest) -> str | None:
|
||||
"""
|
||||
Information about the authentication method which was used for
|
||||
this session is stored in social_auth_backend session attribute.
|
||||
@@ -3098,7 +3098,7 @@ class SAMLSPInitiatedLogout:
|
||||
return authentication_method.split("saml:")[1]
|
||||
|
||||
@classmethod
|
||||
def get_logged_in_user_session_index(cls, request: HttpRequest) -> Optional[str]:
|
||||
def get_logged_in_user_session_index(cls, request: HttpRequest) -> str | None:
|
||||
"""
|
||||
During SAML authentication, we obtain the SessionIndex value provided
|
||||
by the IdP and save it in the session. This function can be used
|
||||
@@ -3112,9 +3112,7 @@ class SAMLSPInitiatedLogout:
|
||||
return session_index
|
||||
|
||||
@classmethod
|
||||
def slo_request_to_idp(
|
||||
cls, request: HttpRequest, return_to: Optional[str] = None
|
||||
) -> HttpResponse:
|
||||
def slo_request_to_idp(cls, request: HttpRequest, return_to: str | None = None) -> HttpResponse:
|
||||
"""
|
||||
Generates the redirect to the IdP's SLO endpoint with
|
||||
the appropriately generated LogoutRequest. This should only be called
|
||||
@@ -3163,7 +3161,7 @@ class SAMLSPInitiatedLogout:
|
||||
return HttpResponseRedirect(settings.LOGIN_URL)
|
||||
|
||||
|
||||
def get_external_method_dicts(realm: Optional[Realm] = None) -> list[ExternalAuthMethodDictT]:
|
||||
def get_external_method_dicts(realm: Realm | None = None) -> list[ExternalAuthMethodDictT]:
|
||||
"""
|
||||
Returns a list of dictionaries that represent social backends, sorted
|
||||
in the order in which they should be displayed.
|
||||
|
@@ -3,7 +3,7 @@ import os
|
||||
import sys
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from typing import Any, Final, Literal, Union
|
||||
from typing import Any, Final, Literal
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from scripts.lib.zulip_tools import get_tornado_ports
|
||||
@@ -576,7 +576,7 @@ else:
|
||||
########################################################################
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
LOADERS: list[Union[str, tuple[object, ...]]] = [
|
||||
LOADERS: list[str | tuple[object, ...]] = [
|
||||
"django.template.loaders.filesystem.Loader",
|
||||
"django.template.loaders.app_directories.Loader",
|
||||
]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import configparser
|
||||
import os
|
||||
from typing import Optional, Union, overload
|
||||
from typing import overload
|
||||
|
||||
from scripts.lib.zulip_tools import get_config as get_config_from_file
|
||||
|
||||
@@ -27,12 +27,12 @@ else:
|
||||
@overload
|
||||
def get_secret(
|
||||
key: str, default_value: None = None, development_only: bool = False
|
||||
) -> Optional[str]: ...
|
||||
) -> str | None: ...
|
||||
@overload
|
||||
def get_secret(key: str, default_value: str, development_only: bool = False) -> str: ...
|
||||
def get_secret(
|
||||
key: str, default_value: Optional[str] = None, development_only: bool = False
|
||||
) -> Optional[str]:
|
||||
key: str, default_value: str | None = None, development_only: bool = False
|
||||
) -> str | None:
|
||||
if development_only and PRODUCTION: # nocoverage
|
||||
return default_value
|
||||
return secrets_file.get("secrets", key, fallback=default_value)
|
||||
@@ -48,14 +48,14 @@ def get_mandatory_secret(key: str) -> str:
|
||||
|
||||
|
||||
@overload
|
||||
def get_config(section: str, key: str, default_value: None = None) -> Optional[str]: ...
|
||||
def get_config(section: str, key: str, default_value: None = None) -> str | None: ...
|
||||
@overload
|
||||
def get_config(section: str, key: str, default_value: str) -> str: ...
|
||||
@overload
|
||||
def get_config(section: str, key: str, default_value: bool) -> bool: ...
|
||||
def get_config(
|
||||
section: str, key: str, default_value: Union[str, bool, None] = None
|
||||
) -> Union[str, bool, None]:
|
||||
section: str, key: str, default_value: str | bool | None = None
|
||||
) -> str | bool | None:
|
||||
return get_config_from_file(config_file, section, key, default_value)
|
||||
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from email.headerregistry import Address
|
||||
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional
|
||||
|
||||
from django_auth_ldap.config import GroupOfUniqueNamesType, LDAPGroupType
|
||||
|
||||
@@ -21,7 +21,7 @@ DEBUG = DEVELOPMENT
|
||||
|
||||
EXTERNAL_HOST_WITHOUT_PORT = deport(EXTERNAL_HOST)
|
||||
|
||||
STATIC_URL: Optional[str] = None
|
||||
STATIC_URL: str | None = None
|
||||
|
||||
# These settings are intended for the server admin to set. We document them in
|
||||
# prod_settings_template.py, and in the initial /etc/zulip/settings.py on a new
|
||||
@@ -40,7 +40,7 @@ PHYSICAL_ADDRESS = ""
|
||||
FAKE_EMAIL_DOMAIN = EXTERNAL_HOST_WITHOUT_PORT
|
||||
|
||||
# SMTP settings
|
||||
EMAIL_HOST: Optional[str] = None
|
||||
EMAIL_HOST: str | None = None
|
||||
# Other settings, like EMAIL_HOST_USER, EMAIL_PORT, and EMAIL_USE_TLS,
|
||||
# we leave up to Django's defaults.
|
||||
|
||||
@@ -48,17 +48,17 @@ EMAIL_HOST: Optional[str] = None
|
||||
AUTH_LDAP_SERVER_URI = ""
|
||||
AUTH_LDAP_BIND_DN = ""
|
||||
AUTH_LDAP_USER_SEARCH: Optional["LDAPSearch"] = None
|
||||
LDAP_APPEND_DOMAIN: Optional[str] = None
|
||||
LDAP_EMAIL_ATTR: Optional[str] = None
|
||||
LDAP_APPEND_DOMAIN: str | None = None
|
||||
LDAP_EMAIL_ATTR: str | None = None
|
||||
AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
|
||||
AUTH_LDAP_USERNAME_ATTR: Optional[str] = None
|
||||
AUTH_LDAP_USERNAME_ATTR: str | None = None
|
||||
# AUTH_LDAP_USER_ATTR_MAP is uncommented in prod_settings_template.py,
|
||||
# so the value here mainly serves to help document the default.
|
||||
AUTH_LDAP_USER_ATTR_MAP: dict[str, str] = {
|
||||
"full_name": "cn",
|
||||
}
|
||||
# Automatically deactivate users not found by the AUTH_LDAP_USER_SEARCH query.
|
||||
LDAP_DEACTIVATE_NON_MATCHING_USERS: Optional[bool] = None
|
||||
LDAP_DEACTIVATE_NON_MATCHING_USERS: bool | None = None
|
||||
# AUTH_LDAP_CONNECTION_OPTIONS: we set ldap.OPT_REFERRALS in settings.py if unset.
|
||||
AUTH_LDAP_CONNECTION_OPTIONS: dict[int, object] = {}
|
||||
# Disable django-auth-ldap caching, to prevent problems with OU changes.
|
||||
@@ -68,28 +68,28 @@ AUTH_LDAP_ALWAYS_UPDATE_USER = False
|
||||
# Development-only settings for fake LDAP authentication; used to
|
||||
# support local development of LDAP auth without an LDAP server.
|
||||
# Detailed docs in zproject/dev_settings.py.
|
||||
FAKE_LDAP_MODE: Optional[str] = None
|
||||
FAKE_LDAP_MODE: str | None = None
|
||||
FAKE_LDAP_NUM_USERS = 8
|
||||
AUTH_LDAP_ADVANCED_REALM_ACCESS_CONTROL: Optional[dict[str, Any]] = None
|
||||
AUTH_LDAP_ADVANCED_REALM_ACCESS_CONTROL: dict[str, Any] | None = None
|
||||
LDAP_SYNCHRONIZED_GROUPS_BY_REALM: dict[str, list[str]] = {}
|
||||
AUTH_LDAP_GROUP_TYPE: LDAPGroupType = GroupOfUniqueNamesType()
|
||||
|
||||
# Social auth; we support providing values for some of these
|
||||
# settings in zulip-secrets.conf instead of settings.py in development.
|
||||
SOCIAL_AUTH_GITHUB_KEY = get_secret("social_auth_github_key", development_only=True)
|
||||
SOCIAL_AUTH_GITHUB_ORG_NAME: Optional[str] = None
|
||||
SOCIAL_AUTH_GITHUB_TEAM_ID: Optional[str] = None
|
||||
SOCIAL_AUTH_GITHUB_ORG_NAME: str | None = None
|
||||
SOCIAL_AUTH_GITHUB_TEAM_ID: str | None = None
|
||||
SOCIAL_AUTH_GITLAB_KEY = get_secret("social_auth_gitlab_key", development_only=True)
|
||||
SOCIAL_AUTH_SUBDOMAIN: Optional[str] = None
|
||||
SOCIAL_AUTH_SUBDOMAIN: str | None = None
|
||||
SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = get_secret("social_auth_azuread_oauth2_key", development_only=True)
|
||||
SOCIAL_AUTH_GOOGLE_KEY = get_secret("social_auth_google_key", development_only=True)
|
||||
# SAML:
|
||||
SOCIAL_AUTH_SAML_SP_ENTITY_ID: Optional[str] = None
|
||||
SOCIAL_AUTH_SAML_SP_ENTITY_ID: str | None = None
|
||||
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT = ""
|
||||
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY = ""
|
||||
SOCIAL_AUTH_SAML_ORG_INFO: Optional[dict[str, dict[str, str]]] = None
|
||||
SOCIAL_AUTH_SAML_TECHNICAL_CONTACT: Optional[dict[str, str]] = None
|
||||
SOCIAL_AUTH_SAML_SUPPORT_CONTACT: Optional[dict[str, str]] = None
|
||||
SOCIAL_AUTH_SAML_ORG_INFO: dict[str, dict[str, str]] | None = None
|
||||
SOCIAL_AUTH_SAML_TECHNICAL_CONTACT: dict[str, str] | None = None
|
||||
SOCIAL_AUTH_SAML_SUPPORT_CONTACT: dict[str, str] | None = None
|
||||
SOCIAL_AUTH_SAML_ENABLED_IDPS: dict[str, SAMLIdPConfigDict] = {}
|
||||
SOCIAL_AUTH_SAML_SECURITY_CONFIG: dict[str, Any] = {}
|
||||
# Set this to True to enforce that any configured IdP needs to specify
|
||||
@@ -97,7 +97,7 @@ SOCIAL_AUTH_SAML_SECURITY_CONFIG: dict[str, Any] = {}
|
||||
SAML_REQUIRE_LIMIT_TO_SUBDOMAINS = False
|
||||
|
||||
# Historical name for SOCIAL_AUTH_GITHUB_KEY; still allowed in production.
|
||||
GOOGLE_OAUTH2_CLIENT_ID: Optional[str] = None
|
||||
GOOGLE_OAUTH2_CLIENT_ID: str | None = None
|
||||
|
||||
# Apple:
|
||||
SOCIAL_AUTH_APPLE_SERVICES_ID = get_secret("social_auth_apple_services_id", development_only=True)
|
||||
@@ -114,20 +114,20 @@ SOCIAL_AUTH_OIDC_FULL_NAME_VALIDATED = False
|
||||
SOCIAL_AUTH_SYNC_CUSTOM_ATTRS_DICT: dict[str, dict[str, dict[str, str]]] = {}
|
||||
|
||||
# Other auth
|
||||
SSO_APPEND_DOMAIN: Optional[str] = None
|
||||
CUSTOM_HOME_NOT_LOGGED_IN: Optional[str] = None
|
||||
SSO_APPEND_DOMAIN: str | None = None
|
||||
CUSTOM_HOME_NOT_LOGGED_IN: str | None = None
|
||||
|
||||
VIDEO_ZOOM_CLIENT_ID = get_secret("video_zoom_client_id", development_only=True)
|
||||
VIDEO_ZOOM_CLIENT_SECRET = get_secret("video_zoom_client_secret")
|
||||
|
||||
# Email gateway
|
||||
EMAIL_GATEWAY_PATTERN = ""
|
||||
EMAIL_GATEWAY_LOGIN: Optional[str] = None
|
||||
EMAIL_GATEWAY_IMAP_SERVER: Optional[str] = None
|
||||
EMAIL_GATEWAY_IMAP_PORT: Optional[int] = None
|
||||
EMAIL_GATEWAY_IMAP_FOLDER: Optional[str] = None
|
||||
EMAIL_GATEWAY_LOGIN: str | None = None
|
||||
EMAIL_GATEWAY_IMAP_SERVER: str | None = None
|
||||
EMAIL_GATEWAY_IMAP_PORT: int | None = None
|
||||
EMAIL_GATEWAY_IMAP_FOLDER: str | None = None
|
||||
# Not documented for in /etc/zulip/settings.py, since it's rarely needed.
|
||||
EMAIL_GATEWAY_EXTRA_PATTERN_HACK: Optional[str] = None
|
||||
EMAIL_GATEWAY_EXTRA_PATTERN_HACK: str | None = None
|
||||
|
||||
# Error reporting
|
||||
ERROR_REPORTING = True
|
||||
@@ -135,22 +135,22 @@ LOGGING_SHOW_MODULE = False
|
||||
LOGGING_SHOW_PID = False
|
||||
|
||||
# Sentry.io error defaults to off
|
||||
SENTRY_DSN: Optional[str] = get_config("sentry", "project_dsn", None)
|
||||
SENTRY_TRACE_WORKER_RATE: Union[float, dict[str, float]] = 0.0
|
||||
SENTRY_DSN: str | None = get_config("sentry", "project_dsn", None)
|
||||
SENTRY_TRACE_WORKER_RATE: float | dict[str, float] = 0.0
|
||||
SENTRY_TRACE_RATE: float = 0.0
|
||||
SENTRY_PROFILE_RATE: float = 0.1
|
||||
SENTRY_FRONTEND_DSN: Optional[str] = get_config("sentry", "frontend_project_dsn", None)
|
||||
SENTRY_FRONTEND_DSN: str | None = get_config("sentry", "frontend_project_dsn", None)
|
||||
SENTRY_FRONTEND_SAMPLE_RATE: float = 1.0
|
||||
SENTRY_FRONTEND_TRACE_RATE: float = 0.1
|
||||
|
||||
# File uploads and avatars
|
||||
# TODO: Rename MAX_FILE_UPLOAD_SIZE to have unit in name.
|
||||
DEFAULT_AVATAR_URI: Optional[str] = None
|
||||
DEFAULT_LOGO_URI: Optional[str] = None
|
||||
DEFAULT_AVATAR_URI: str | None = None
|
||||
DEFAULT_LOGO_URI: str | None = None
|
||||
S3_AVATAR_BUCKET = ""
|
||||
S3_AUTH_UPLOADS_BUCKET = ""
|
||||
S3_REGION: Optional[str] = None
|
||||
S3_ENDPOINT_URL: Optional[str] = None
|
||||
S3_REGION: str | None = None
|
||||
S3_ENDPOINT_URL: str | None = None
|
||||
S3_ADDRESSING_STYLE: Literal["auto", "virtual", "path"] = "auto"
|
||||
S3_SKIP_PROXY = True
|
||||
S3_UPLOADS_STORAGE_CLASS: Literal[
|
||||
@@ -161,17 +161,17 @@ S3_UPLOADS_STORAGE_CLASS: Literal[
|
||||
"STANDARD",
|
||||
"STANDARD_IA",
|
||||
] = "STANDARD"
|
||||
S3_AVATAR_PUBLIC_URL_PREFIX: Optional[str] = None
|
||||
LOCAL_UPLOADS_DIR: Optional[str] = None
|
||||
LOCAL_AVATARS_DIR: Optional[str] = None
|
||||
LOCAL_FILES_DIR: Optional[str] = None
|
||||
S3_AVATAR_PUBLIC_URL_PREFIX: str | None = None
|
||||
LOCAL_UPLOADS_DIR: str | None = None
|
||||
LOCAL_AVATARS_DIR: str | None = None
|
||||
LOCAL_FILES_DIR: str | None = None
|
||||
MAX_FILE_UPLOAD_SIZE = 25
|
||||
# How many GB an organization on a paid plan can upload per user,
|
||||
# on zulipchat.com.
|
||||
UPLOAD_QUOTA_PER_USER_GB = 5
|
||||
|
||||
# Jitsi Meet video call integration; set to None to disable integration.
|
||||
JITSI_SERVER_URL: Optional[str] = "https://meet.jit.si"
|
||||
JITSI_SERVER_URL: str | None = "https://meet.jit.si"
|
||||
|
||||
# GIPHY API key.
|
||||
GIPHY_API_KEY = get_secret("giphy_api_key")
|
||||
@@ -217,7 +217,7 @@ NAME_CHANGES_DISABLED = False
|
||||
AVATAR_CHANGES_DISABLED = False
|
||||
PASSWORD_MIN_LENGTH = 6
|
||||
PASSWORD_MIN_GUESSES = 10000
|
||||
PUSH_NOTIFICATION_BOUNCER_URL: Optional[str] = None
|
||||
PUSH_NOTIFICATION_BOUNCER_URL: str | None = None
|
||||
PUSH_NOTIFICATION_REDACT_CONTENT = False
|
||||
SUBMIT_USAGE_STATISTICS = True
|
||||
PROMOTE_SPONSORING_ZULIP = True
|
||||
@@ -399,7 +399,7 @@ USING_PGROONGA = False
|
||||
|
||||
# How Django should send emails. Set for most contexts in settings.py, but
|
||||
# available for sysadmin override in unusual cases.
|
||||
EMAIL_BACKEND: Optional[str] = None
|
||||
EMAIL_BACKEND: str | None = None
|
||||
|
||||
# Whether to give admins a warning in the web app that email isn't set up.
|
||||
# Set in settings.py when email isn't configured.
|
||||
@@ -418,14 +418,14 @@ POST_MIGRATION_CACHE_FLUSHING = False
|
||||
# Settings for APNS. Only needed on push.zulipchat.com or if
|
||||
# rebuilding the mobile app with a different push notifications
|
||||
# server.
|
||||
APNS_CERT_FILE: Optional[str] = None
|
||||
APNS_TOKEN_KEY_FILE: Optional[str] = None
|
||||
APNS_CERT_FILE: str | None = None
|
||||
APNS_TOKEN_KEY_FILE: str | None = None
|
||||
APNS_TOKEN_KEY_ID = get_secret("apns_token_key_id", development_only=True)
|
||||
APNS_TEAM_ID = get_secret("apns_team_id", development_only=True)
|
||||
APNS_SANDBOX = True
|
||||
# APNS_TOPIC is obsolete. Clients now pass the APNs topic to use.
|
||||
# ZULIP_IOS_APP_ID is obsolete. Clients now pass the iOS app ID to use for APNs.
|
||||
ANDROID_FCM_CREDENTIALS_PATH: Optional[str] = None
|
||||
ANDROID_FCM_CREDENTIALS_PATH: str | None = None
|
||||
|
||||
# Limits related to the size of file uploads; last few in MB.
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = 25 * 1024 * 1024
|
||||
@@ -448,7 +448,7 @@ INVITES_NEW_REALM_LIMIT_DAYS = [(1, 100)]
|
||||
INVITES_NEW_REALM_DAYS = 7
|
||||
|
||||
# Controls for which links are published in portico footers/headers/etc.
|
||||
REGISTER_LINK_DISABLED: Optional[bool] = None
|
||||
REGISTER_LINK_DISABLED: bool | None = None
|
||||
LOGIN_LINK_DISABLED = False
|
||||
FIND_TEAM_LINK_DISABLED = True
|
||||
|
||||
@@ -458,11 +458,11 @@ ROOT_SUBDOMAIN_ALIASES = ["www"]
|
||||
ROOT_DOMAIN_LANDING_PAGE = False
|
||||
|
||||
# Subdomain for serving endpoints to users from self-hosted deployments.
|
||||
SELF_HOSTING_MANAGEMENT_SUBDOMAIN: Optional[str] = None
|
||||
SELF_HOSTING_MANAGEMENT_SUBDOMAIN: str | None = None
|
||||
|
||||
# If using the Zephyr mirroring supervisord configuration, the
|
||||
# hostname to connect to in order to transfer credentials from webathena.
|
||||
PERSONAL_ZMIRROR_SERVER: Optional[str] = None
|
||||
PERSONAL_ZMIRROR_SERVER: str | None = None
|
||||
|
||||
# When security-relevant links in emails expire.
|
||||
CONFIRMATION_LINK_DEFAULT_VALIDITY_DAYS = 1
|
||||
@@ -472,17 +472,17 @@ REALM_CREATION_LINK_VALIDITY_DAYS = 7
|
||||
# Version number for ToS. Change this if you want to force every
|
||||
# user to click through to re-accept terms of service before using
|
||||
# Zulip again on the web.
|
||||
TERMS_OF_SERVICE_VERSION: Optional[str] = None
|
||||
TERMS_OF_SERVICE_VERSION: str | None = None
|
||||
# HTML template path (e.g. "corporate/zulipchat_migration_tos.html")
|
||||
# displayed to users when increasing TERMS_OF_SERVICE_VERSION when a
|
||||
# user is to accept the terms of service for the first time, but
|
||||
# already has an account. This primarily comes up when doing a data
|
||||
# import.
|
||||
FIRST_TIME_TERMS_OF_SERVICE_TEMPLATE: Optional[str] = None
|
||||
FIRST_TIME_TERMS_OF_SERVICE_TEMPLATE: str | None = None
|
||||
# Custom message (HTML allowed) to be displayed to explain why users
|
||||
# need to re-accept the terms of service when a new major version is
|
||||
# written.
|
||||
TERMS_OF_SERVICE_MESSAGE: Optional[str] = None
|
||||
TERMS_OF_SERVICE_MESSAGE: str | None = None
|
||||
|
||||
# Configuration for JWT auth (sign in and API key fetch)
|
||||
JWT_AUTH_KEYS: dict[str, JwtAuthKey] = {}
|
||||
@@ -494,7 +494,7 @@ SERVER_EMAIL = ZULIP_ADMINISTRATOR
|
||||
ADMINS = (("Zulip Administrator", ZULIP_ADMINISTRATOR),)
|
||||
|
||||
# From address for welcome emails.
|
||||
WELCOME_EMAIL_SENDER: Optional[dict[str, str]] = None
|
||||
WELCOME_EMAIL_SENDER: dict[str, str] | None = None
|
||||
|
||||
# Whether to send periodic digests of activity.
|
||||
SEND_DIGEST_EMAILS = True
|
||||
@@ -502,11 +502,11 @@ SEND_DIGEST_EMAILS = True
|
||||
INSTALLATION_NAME = EXTERNAL_HOST
|
||||
|
||||
# Used to change the Zulip logo in portico pages.
|
||||
CUSTOM_LOGO_URL: Optional[str] = None
|
||||
CUSTOM_LOGO_URL: str | None = None
|
||||
|
||||
# Random salt used when deterministically generating passwords in
|
||||
# development.
|
||||
INITIAL_PASSWORD_SALT: Optional[str] = None
|
||||
INITIAL_PASSWORD_SALT: str | None = None
|
||||
|
||||
# Settings configuring the special instrumentation of the send_event
|
||||
# code path used in generating API documentation for /events.
|
||||
@@ -559,12 +559,12 @@ ARCHIVED_DATA_VACUUMING_DELAY_DAYS = 30
|
||||
# are available to all realms.
|
||||
BILLING_ENABLED = False
|
||||
|
||||
CLOUD_FREE_TRIAL_DAYS: Optional[int] = int(get_secret("cloud_free_trial_days", "0"))
|
||||
SELF_HOSTING_FREE_TRIAL_DAYS: Optional[int] = int(get_secret("self_hosting_free_trial_days", "30"))
|
||||
CLOUD_FREE_TRIAL_DAYS: int | None = int(get_secret("cloud_free_trial_days", "0"))
|
||||
SELF_HOSTING_FREE_TRIAL_DAYS: int | None = int(get_secret("self_hosting_free_trial_days", "30"))
|
||||
|
||||
# Custom message (supports HTML) to be shown in the navbar of landing pages. Used mainly for
|
||||
# making announcements.
|
||||
LANDING_PAGE_NAVBAR_MESSAGE: Optional[str] = None
|
||||
LANDING_PAGE_NAVBAR_MESSAGE: str | None = None
|
||||
|
||||
# Automatically catch-up soft deactivated users when running the
|
||||
# `soft-deactivate-users` cron. Turn this off if the server has 10Ks of
|
||||
@@ -573,7 +573,7 @@ LANDING_PAGE_NAVBAR_MESSAGE: Optional[str] = None
|
||||
AUTO_CATCH_UP_SOFT_DEACTIVATED_USERS = True
|
||||
|
||||
# Enables Google Analytics on selected portico pages.
|
||||
GOOGLE_ANALYTICS_ID: Optional[str] = None
|
||||
GOOGLE_ANALYTICS_ID: str | None = None
|
||||
|
||||
# This is overridden by dev_settings.py for droplets.
|
||||
IS_DEV_DROPLET = False
|
||||
@@ -636,7 +636,7 @@ CAN_ACCESS_ALL_USERS_GROUP_LIMITS_PRESENCE = False
|
||||
# in some places through the codebase.
|
||||
SIGNED_ACCESS_TOKEN_VALIDITY_IN_SECONDS = 60
|
||||
|
||||
CUSTOM_AUTHENTICATION_WRAPPER_FUNCTION: Optional[Callable[..., Any]] = None
|
||||
CUSTOM_AUTHENTICATION_WRAPPER_FUNCTION: Callable[..., Any] | None = None
|
||||
|
||||
# Whether we allow settings to be set to a collection of users and
|
||||
# groups as described in api_docs/group-setting-values.md. Set to
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
import pwd
|
||||
from typing import Optional
|
||||
|
||||
from scripts.lib.zulip_tools import deport
|
||||
from zproject.settings_types import SCIMConfigDict
|
||||
@@ -94,7 +93,7 @@ LOGIN_URL = "/devlogin/"
|
||||
# For development convenience, configure the ToS/Privacy Policies
|
||||
POLICIES_DIRECTORY = "corporate/policies"
|
||||
TERMS_OF_SERVICE_VERSION = "1.0"
|
||||
TERMS_OF_SERVICE_MESSAGE: Optional[str] = "Description of changes to the ToS!"
|
||||
TERMS_OF_SERVICE_MESSAGE: str | None = "Description of changes to the ToS!"
|
||||
|
||||
EMBEDDED_BOTS_ENABLED = True
|
||||
|
||||
@@ -133,7 +132,7 @@ TWO_FACTOR_SMS_GATEWAY = "two_factor.gateways.fake.Fake"
|
||||
# (C) If LDAP usernames are completely unrelated to email addresses.
|
||||
#
|
||||
# Fake LDAP data has e.g. ("ldapuser1", "ldapuser1@zulip.com") for username/email.
|
||||
FAKE_LDAP_MODE: Optional[str] = None
|
||||
FAKE_LDAP_MODE: str | None = None
|
||||
# FAKE_LDAP_NUM_USERS = 8
|
||||
|
||||
if FAKE_LDAP_MODE:
|
||||
@@ -180,7 +179,7 @@ if FAKE_LDAP_MODE:
|
||||
AUTHENTICATION_BACKENDS += ("zproject.backends.ZulipLDAPAuthBackend",)
|
||||
|
||||
BILLING_ENABLED = True
|
||||
LANDING_PAGE_NAVBAR_MESSAGE: Optional[str] = None
|
||||
LANDING_PAGE_NAVBAR_MESSAGE: str | None = None
|
||||
|
||||
# Our run-dev proxy uses X-Forwarded-Port to communicate to Django
|
||||
# that the request is actually on port 9991, not port 9992 (the Django
|
||||
@@ -194,7 +193,7 @@ SOCIAL_AUTH_SAML_SP_ENTITY_ID = "http://localhost:9991"
|
||||
|
||||
SOCIAL_AUTH_SUBDOMAIN = "auth"
|
||||
|
||||
MEMCACHED_USERNAME: Optional[str] = None
|
||||
MEMCACHED_USERNAME: str | None = None
|
||||
|
||||
SCIM_CONFIG: dict[str, SCIMConfigDict] = {
|
||||
"zulip": {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import configparser
|
||||
import logging
|
||||
from email.message import Message
|
||||
from typing import MutableSequence, Sequence, Union
|
||||
from typing import MutableSequence, Sequence
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
@@ -37,7 +37,7 @@ class EmailLogBackEnd(EmailBackend):
|
||||
@staticmethod
|
||||
def log_email(email: EmailMessage) -> None:
|
||||
"""Used in development to record sent emails in a nice HTML log"""
|
||||
html_message: Union[bytes, EmailMessage, Message, str] = "Missing HTML message"
|
||||
html_message: bytes | EmailMessage | Message | str = "Missing HTML message"
|
||||
assert isinstance(email, EmailMultiAlternatives)
|
||||
if len(email.alternatives) > 0:
|
||||
html_message = email.alternatives[0][0]
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
import sentry_sdk
|
||||
from django.utils.translation import override as override_language
|
||||
@@ -50,7 +50,7 @@ def add_context(event: "Event", hint: "Hint") -> Optional["Event"]:
|
||||
return event
|
||||
|
||||
|
||||
def traces_sampler(sampling_context: dict[str, Any]) -> Union[float, bool]:
|
||||
def traces_sampler(sampling_context: dict[str, Any]) -> float | bool:
|
||||
from django.conf import settings
|
||||
|
||||
queue = sampling_context.get("queue")
|
||||
@@ -63,7 +63,7 @@ def traces_sampler(sampling_context: dict[str, Any]) -> Union[float, bool]:
|
||||
return settings.SENTRY_TRACE_RATE
|
||||
|
||||
|
||||
def setup_sentry(dsn: Optional[str], environment: str) -> None:
|
||||
def setup_sentry(dsn: str | None, environment: str) -> None:
|
||||
from django.conf import settings
|
||||
|
||||
if not dsn:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from typing import Optional, TypedDict
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class JwtAuthKey(TypedDict):
|
||||
@@ -31,9 +31,9 @@ class SAMLIdPConfigDict(TypedDict, total=False):
|
||||
class OIDCIdPConfigDict(TypedDict, total=False):
|
||||
oidc_url: str
|
||||
display_name: str
|
||||
display_icon: Optional[str]
|
||||
display_icon: str | None
|
||||
client_id: str
|
||||
secret: Optional[str]
|
||||
secret: str | None
|
||||
auto_signup: bool
|
||||
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from django.template.loaders import app_directories
|
||||
from typing_extensions import override
|
||||
@@ -7,11 +6,11 @@ from typing_extensions import override
|
||||
|
||||
class TwoFactorLoader(app_directories.Loader):
|
||||
@override
|
||||
def get_dirs(self) -> list[Union[str, Path]]:
|
||||
def get_dirs(self) -> list[str | Path]:
|
||||
dirs = super().get_dirs()
|
||||
# app_directories.Loader returns only a list of
|
||||
# Path objects by calling get_app_template_dirs
|
||||
two_factor_dirs: list[Union[str, Path]] = []
|
||||
two_factor_dirs: list[str | Path] = []
|
||||
for d in dirs:
|
||||
assert isinstance(d, Path)
|
||||
if d.match("two_factor/*"):
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
import ldap
|
||||
from django_auth_ldap.config import LDAPSearch
|
||||
@@ -155,8 +154,8 @@ HOME_NOT_LOGGED_IN = "/login/"
|
||||
LOGIN_URL = "/accounts/login/"
|
||||
|
||||
# If dev_settings.py found a key or cert file to use here, ignore it.
|
||||
APNS_TOKEN_KEY_FILE: Optional[str] = None
|
||||
APNS_CERT_FILE: Optional[str] = None
|
||||
APNS_TOKEN_KEY_FILE: str | None = None
|
||||
APNS_CERT_FILE: str | None = None
|
||||
|
||||
# By default will not send emails when login occurs.
|
||||
# Explicitly set this to True within tests that must have this on.
|
||||
@@ -202,7 +201,7 @@ BIG_BLUE_BUTTON_URL = "https://bbb.example.com/bigbluebutton/"
|
||||
# By default two factor authentication is disabled in tests.
|
||||
# Explicitly set this to True within tests that must have this on.
|
||||
TWO_FACTOR_AUTHENTICATION_ENABLED = False
|
||||
PUSH_NOTIFICATION_BOUNCER_URL: Optional[str] = None
|
||||
PUSH_NOTIFICATION_BOUNCER_URL: str | None = None
|
||||
DEVELOPMENT_DISABLE_PUSH_BOUNCER_DOMAIN_CHECK = False
|
||||
|
||||
# Logging the emails while running the tests adds them
|
||||
@@ -258,8 +257,8 @@ RATE_LIMITING_RULES: dict[str, list[tuple[int, int]]] = {
|
||||
"sends_email_by_remote_server": [],
|
||||
}
|
||||
|
||||
CLOUD_FREE_TRIAL_DAYS: Optional[int] = None
|
||||
SELF_HOSTING_FREE_TRIAL_DAYS: Optional[int] = None
|
||||
CLOUD_FREE_TRIAL_DAYS: int | None = None
|
||||
SELF_HOSTING_FREE_TRIAL_DAYS: int | None = None
|
||||
|
||||
SCIM_CONFIG: dict[str, SCIMConfigDict] = {
|
||||
"zulip": {
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import os
|
||||
from typing import Union
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include
|
||||
@@ -632,7 +631,7 @@ i18n_urls = [
|
||||
]
|
||||
|
||||
# Make a copy of i18n_urls so that they appear without prefix for english
|
||||
urls: list[Union[URLPattern, URLResolver]] = list(i18n_urls)
|
||||
urls: list[URLPattern | URLResolver] = list(i18n_urls)
|
||||
|
||||
# Include the dual-use patterns twice
|
||||
urls += [
|
||||
|
Reference in New Issue
Block a user