def api_get_server_settings(request: HttpRequest) -> HttpResponse: # Log which client is making this request. process_client(request, request.user, skip_update_user_activity=True) result = dict( authentication_methods=get_auth_backends_data(request), zulip_version=ZULIP_VERSION, push_notifications_enabled=push_notifications_enabled(), is_incompatible=check_server_incompatibility(request), ) context = zulip_default_context(request) # IMPORTANT NOTE: # realm_name, realm_icon, etc. are not guaranteed to appear in the response. # * If they do, that means the server URL has only one realm on it # * If they don't, the server has multiple realms, and it's not clear which is # the requested realm, so we can't send back these data. for settings_item in [ "email_auth_enabled", "require_email_format_usernames", "realm_uri", "realm_name", "realm_icon", "realm_logo", "realm_description"]: if context[settings_item] is not None: result[settings_item] = context[settings_item] return json_success(result)
def api_fetch_api_key( request: HttpRequest, username: str = REQ(), password: str = REQ() ) -> HttpResponse: return_data = {} # type: Dict[str, bool] subdomain = get_subdomain(request) realm = get_realm(subdomain) if username == "google-oauth2-token": # This code path is auth for the legacy Android app user_profile = authenticate(google_oauth2_token=password, realm=realm, return_data=return_data) else: if not ldap_auth_enabled(realm=get_realm_from_request(request)): # In case we don't authenticate against LDAP, check for a valid # email. LDAP backend can authenticate against a non-email. validate_login_email(username) user_profile = authenticate(username=username, password=password, realm=realm, return_data=return_data) if return_data.get("inactive_user"): return json_error(_("Your account has been disabled."), data={"reason": "user disable"}, status=403) if return_data.get("inactive_realm"): return json_error(_("This organization has been deactivated."), data={"reason": "realm deactivated"}, status=403) if return_data.get("password_auth_disabled"): return json_error(_("Password auth is disabled in your team."), data={"reason": "password auth disabled"}, status=403) if user_profile is None: if return_data.get("valid_attestation"): # We can leak that the user is unregistered iff # they present a valid authentication string for the user. return json_error( _("This user is not registered; do so from a browser."), data={"reason": "unregistered"}, status=403) return json_error(_("Your username or password is incorrect."), data={"reason": "incorrect_creds"}, status=403) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email api_key = get_api_key(user_profile) return json_success({"api_key": api_key, "email": user_profile.email})
def get_events_internal( request: HttpRequest, user_profile_id: int = REQ(validator=check_int) ) -> HttpResponse: user_profile = get_user_profile_by_id(user_profile_id) request._email = user_profile.delivery_email process_client(request, user_profile, client_name="internal") return get_events_backend(request, user_profile)
def get_events_internal( request: HttpRequest, user_profile_id: int = REQ(validator=check_int) ) -> HttpResponse: user_profile = get_user_profile_by_id(user_profile_id) request._requestor_for_logs = user_profile.format_requestor_for_logs() process_client(request, user_profile, client_name="internal") return get_events_backend(request, user_profile)
def finish_mobile_flow(request: HttpRequest, user_profile: UserProfile, otp: str) -> HttpResponse: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. api_key = get_api_key(user_profile) response = create_response_for_otp_flow( api_key, otp, user_profile, encrypted_key_field_name='otp_encrypted_api_key') # Since we are returning an API key instead of going through # the Django login() function (which creates a browser # session, etc.), the "new login" signal handler (which # triggers an email notification new logins) will not run # automatically. So we call it manually here. # # Arguably, sending a fake 'user_logged_in' signal would be a better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.delivery_email return response
def get_events_internal( request: HttpRequest, handler: BaseHandler, user_profile_id: int = REQ() ) -> Union[HttpResponse, _RespondAsynchronously]: user_profile = get_user_profile_by_id(user_profile_id) request._email = user_profile.email process_client(request, user_profile, client_name="internal") return get_events_backend(request, user_profile, handler)
def api_get_server_settings(request: HttpRequest) -> HttpResponse: # Log which client is making this request. process_client(request, request.user, skip_update_user_activity=True) result = dict( authentication_methods=get_auth_backends_data(request), zulip_version=ZULIP_VERSION, zulip_feature_level=API_FEATURE_LEVEL, push_notifications_enabled=push_notifications_enabled(), is_incompatible=check_server_incompatibility(request), ) context = zulip_default_context(request) context.update(login_context(request)) # IMPORTANT NOTE: # realm_name, realm_icon, etc. are not guaranteed to appear in the response. # * If they do, that means the server URL has only one realm on it # * If they don't, the server has multiple realms, and it's not clear which is # the requested realm, so we can't send back these data. for settings_item in [ "email_auth_enabled", "require_email_format_usernames", "realm_uri", "realm_name", "realm_icon", "realm_description", "external_authentication_methods", ]: if context[settings_item] is not None: result[settings_item] = context[settings_item] return json_success(result)
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[Text], user_profile: Optional[UserProfile], full_name: Text='', invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None, is_signup: bool=False) -> HttpResponse: if user_profile is None or user_profile.is_mirror_dummy: # Since execution has reached here, we have verified the user # controls an email address (remote_username) but there's no # associated Zulip user account. if is_signup: # If they're trying to sign up, send them over to the PreregistrationUser flow. return maybe_send_to_registration(request, remote_user_to_email(remote_username), full_name, password_required=False) # Otherwise, we send them to a special page that asks if they # want to register or provided the wrong email and want to go back. try: validate_email(remote_username) invalid_email = False except ValidationError: # If email address is invalid, we can't send the user # PreregistrationUser flow. invalid_email = True context = {'full_name': full_name, 'email': remote_username, 'invalid_email': invalid_email} return render(request, 'zerver/confirm_continue_registration.html', context=context) if invalid_subdomain: # Show login page with an error message return redirect_to_subdomain_login_url() if mobile_flow_otp is not None: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. params = { 'otp_encrypted_api_key': otp_encrypt_api_key(user_profile, mobile_flow_otp), 'email': remote_username, 'realm': user_profile.realm.uri, } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email return response do_login(request, user_profile) return HttpResponseRedirect(user_profile.realm.uri)
def api_fetch_api_key( request: HttpRequest, username: str = REQ(), password: str = REQ() ) -> HttpResponse: return_data: Dict[str, bool] = {} realm = get_realm_from_request(request) if realm is None: return json_error(_("Invalid subdomain")) if not ldap_auth_enabled(realm=realm): # In case we don't authenticate against LDAP, check for a valid # email. LDAP backend can authenticate against a non-email. validate_login_email(username) user_profile = authenticate(request=request, username=username, password=password, realm=realm, return_data=return_data) if return_data.get("inactive_user"): return json_error(_("Your account has been disabled."), data={"reason": "user disable"}, status=403) if return_data.get("inactive_realm"): return json_error( _("This organization has been deactivated."), data={"reason": "realm deactivated"}, status=403, ) if return_data.get("password_auth_disabled"): return json_error( _("Password auth is disabled in your team."), data={"reason": "password auth disabled"}, status=403, ) if user_profile is None: return json_error( _("Your username or password is incorrect."), data={"reason": "incorrect_creds"}, status=403, ) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._requestor_for_logs = user_profile.format_requestor_for_logs() api_key = get_api_key(user_profile) return json_success({ "api_key": api_key, "email": user_profile.delivery_email })
def login_or_register_remote_user(request, remote_username, user_profile, full_name='', invalid_subdomain=False, mobile_flow_otp=None, is_signup=False): # type: (HttpRequest, Optional[Text], Optional[UserProfile], Text, bool, Optional[str], bool) -> HttpResponse if invalid_subdomain: # Show login page with an error message return redirect_to_subdomain_login_url() if user_profile is None or user_profile.is_mirror_dummy: # Since execution has reached here, we have verified the user # controls an email address (remote_username) but there's no # associated Zulip user account. if is_signup: # If they're trying to sign up, send them over to the PreregistrationUser flow. return maybe_send_to_registration(request, remote_user_to_email(remote_username), full_name, password_required=False) # Otherwise, we send them to a special page that asks if they # want to register or provided the wrong email and want to go back. try: validate_email(remote_username) invalid_email = False except ValidationError: # If email address is invalid, we can't send the user # PreregistrationUser flow. invalid_email = True context = {'full_name': full_name, 'email': remote_username, 'invalid_email': invalid_email} return render(request, 'zerver/confirm_continue_registration.html', context=context) if mobile_flow_otp is not None: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. params = { 'otp_encrypted_api_key': otp_encrypt_api_key(user_profile, mobile_flow_otp), 'email': remote_username, 'realm': user_profile.realm.uri, } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email return response do_login(request, user_profile) return HttpResponseRedirect(user_profile.realm.uri)
def login_or_register_remote_user( request: HttpRequest, remote_username: Optional[str], user_profile: Optional[UserProfile], full_name: str = '', invalid_subdomain: bool = False, mobile_flow_otp: Optional[str] = None, is_signup: bool = False, redirect_to: str = '', multiuse_object_key: str = '') -> HttpResponse: email = remote_user_to_email(remote_username) if user_profile is None or user_profile.is_mirror_dummy: # We have verified the user controls an email address, but # there's no associated Zulip user account. Consider sending # the request to registration. return maybe_send_to_registration( request, email, full_name, password_required=False, is_signup=is_signup, multiuse_object_key=multiuse_object_key) # Otherwise, the user has successfully authenticated to an # account, and we need to do the right thing depending whether # or not they're using the mobile OTP flow or want a browser session. if mobile_flow_otp is not None: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. api_key = get_api_key(user_profile) params = { 'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp), 'email': email, 'realm': user_profile.realm.uri, } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) response['Location'] = 'zulip://login?' + urllib.parse.urlencode( params) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email return response do_login(request, user_profile) redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri) return HttpResponseRedirect(redirect_to)
def api_fetch_api_key( request: HttpRequest, username: str = REQ(), password: str = REQ() ) -> HttpResponse: return_data: Dict[str, bool] = {} realm = get_realm_from_request(request) if realm is None: raise InvalidSubdomainError() if not ldap_auth_enabled(realm=realm): # In case we don't authenticate against LDAP, check for a valid # email. LDAP backend can authenticate against a non-email. validate_login_email(username) user_profile = authenticate(request=request, username=username, password=password, realm=realm, return_data=return_data) if return_data.get("inactive_user"): raise UserDeactivatedError() if return_data.get("inactive_realm"): raise RealmDeactivatedError() if return_data.get("password_auth_disabled"): raise PasswordAuthDisabledError() if return_data.get("password_reset_needed"): raise PasswordResetRequiredError() if user_profile is None: raise AuthenticationFailedError() assert user_profile.is_authenticated # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. assert isinstance(user_profile, UserProfile) process_client(request, user_profile) RequestNotes.get_notes( request).requestor_for_logs = user_profile.format_requestor_for_logs() api_key = get_api_key(user_profile) return json_success(request, data={ "api_key": api_key, "email": user_profile.delivery_email })
def api_fetch_api_key(request: HttpRequest, username: str=REQ(), password: str=REQ()) -> HttpResponse: return_data = {} # type: Dict[str, bool] subdomain = get_subdomain(request) realm = get_realm(subdomain) if username == "google-oauth2-token": # This code path is auth for the legacy Android app user_profile = authenticate(google_oauth2_token=password, realm=realm, return_data=return_data) else: if not ldap_auth_enabled(realm=get_realm_from_request(request)): # In case we don't authenticate against LDAP, check for a valid # email. LDAP backend can authenticate against a non-email. validate_login_email(username) user_profile = authenticate(username=username, password=password, realm=realm, return_data=return_data) if return_data.get("inactive_user"): return json_error(_("Your account has been disabled."), data={"reason": "user disable"}, status=403) if return_data.get("inactive_realm"): return json_error(_("This organization has been deactivated."), data={"reason": "realm deactivated"}, status=403) if return_data.get("password_auth_disabled"): return json_error(_("Password auth is disabled in your team."), data={"reason": "password auth disabled"}, status=403) if user_profile is None: if return_data.get("valid_attestation"): # We can leak that the user is unregistered iff # they present a valid authentication string for the user. return json_error(_("This user is not registered; do so from a browser."), data={"reason": "unregistered"}, status=403) return json_error(_("Your username or password is incorrect."), data={"reason": "incorrect_creds"}, status=403) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email api_key = get_api_key(user_profile) return json_success({"api_key": api_key, "email": user_profile.email})
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[str], user_profile: Optional[UserProfile], full_name: str='', invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None, is_signup: bool=False, redirect_to: str='') -> HttpResponse: email = remote_user_to_email(remote_username) if user_profile is None or user_profile.is_mirror_dummy: # We have verified the user controls an email address, but # there's no associated Zulip user account. Consider sending # the request to registration. return maybe_send_to_registration(request, email, full_name, password_required=False, is_signup=is_signup) # Otherwise, the user has successfully authenticated to an # account, and we need to do the right thing depending whether # or not they're using the mobile OTP flow or want a browser session. if mobile_flow_otp is not None: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. api_key = get_api_key(user_profile) params = { 'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp), 'email': email, 'realm': user_profile.realm.uri, } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params) # Maybe sending 'user_logged_in' signal is the better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) # Not doing this only because over here we don't add the user information # in the session. If the signal receiver assumes that we do then that # would cause problems. email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email return response do_login(request, user_profile) redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri) return HttpResponseRedirect(redirect_to)
def home_real(request): # type: (HttpRequest) -> HttpResponse # We need to modify the session object every two weeks or it will expire. # This line makes reloading the page a sufficient action to keep the # session alive. request.session.modified = True user_profile = request.user request._email = request.user.email # Process the client as an auth decorator would process_client(request, user_profile, is_json_view=True) # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[Text]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream_name = request.GET.get("stream") (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name(user_profile, narrow_stream_name) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing") if narrow_stream is not None and narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if user_profile.last_reminder is not None: user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get the tutorial needs_tutorial = settings.TUTORIAL_ENABLED and \ user_profile.tutorial_status != UserProfile.TUTORIAL_FINISHED first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: try: latest_read = UserMessage.objects.get( user_profile=user_profile, message__id=user_profile.pointer) except UserMessage.DoesNotExist: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) latest_read = None desktop_notifications_enabled = user_profile.enable_desktop_notifications if narrow_stream is not None: desktop_notifications_enabled = False if user_profile.realm.notifications_stream: notifications_stream = user_profile.realm.notifications_stream.name else: notifications_stream = "" # Set default language and make it persist default_language = register_ret['default_language'] url_lang = '/{}'.format(request.LANGUAGE_CODE) if not request.path.startswith(url_lang): translation.activate(default_language) request.session[translation.LANGUAGE_SESSION_KEY] = default_language # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( zulip_version=ZULIP_VERSION, share_the_love=settings.SHARE_THE_LOVE, development_environment=settings.DEVELOPMENT, debug_mode=settings.DEBUG, test_suite=settings.TEST_SUITE, poll_timeout=settings.POLL_TIMEOUT, login_page=settings.HOME_NOT_LOGGED_IN, server_uri=settings.SERVER_URI, realm_uri=user_profile.realm.uri, maxfilesize=settings.MAX_FILE_UPLOAD_SIZE, server_generation=settings.SERVER_GENERATION, password_auth_enabled=password_auth_enabled(user_profile.realm), have_initial_messages=user_has_messages, subbed_info=register_ret['subscriptions'], unsubbed_info=register_ret['unsubscribed'], neversubbed_info=register_ret['never_subscribed'], people_list=register_ret['realm_users'], bot_list=register_ret['realm_bots'], initial_pointer=register_ret['pointer'], initial_presences=register_ret['presences'], initial_servertime=time.time( ), # Used for calculating relative presence age fullname=user_profile.full_name, email=user_profile.email, domain=user_profile.realm.domain, domains=list_of_domains_for_realm(user_profile.realm), realm_name=register_ret['realm_name'], realm_invite_required=register_ret['realm_invite_required'], realm_invite_by_admins_only=register_ret[ 'realm_invite_by_admins_only'], realm_authentication_methods=register_ret[ 'realm_authentication_methods'], realm_create_stream_by_admins_only=register_ret[ 'realm_create_stream_by_admins_only'], realm_add_emoji_by_admins_only=register_ret[ 'realm_add_emoji_by_admins_only'], realm_allow_message_editing=register_ret[ 'realm_allow_message_editing'], realm_message_content_edit_limit_seconds=register_ret[ 'realm_message_content_edit_limit_seconds'], realm_restricted_to_domain=register_ret['realm_restricted_to_domain'], realm_default_language=register_ret['realm_default_language'], realm_waiting_period_threshold=register_ret[ 'realm_waiting_period_threshold'], enter_sends=user_profile.enter_sends, user_id=user_profile.id, left_side_userlist=register_ret['left_side_userlist'], default_language=register_ret['default_language'], default_language_name=get_language_name( register_ret['default_language']), language_list_dbl_col=get_language_list_for_templates( register_ret['default_language']), language_list=get_language_list(), referrals=register_ret['referrals'], realm_emoji=register_ret['realm_emoji'], needs_tutorial=needs_tutorial, first_in_realm=first_in_realm, prompt_for_invites=prompt_for_invites, notifications_stream=notifications_stream, cross_realm_bots=list(get_cross_realm_dicts()), use_websockets=settings.USE_WEBSOCKETS, # Stream message notification settings: stream_desktop_notifications_enabled=user_profile. enable_stream_desktop_notifications, stream_sounds_enabled=user_profile.enable_stream_sounds, # Private message and @-mention notification settings: desktop_notifications_enabled=desktop_notifications_enabled, sounds_enabled=user_profile.enable_sounds, enable_offline_email_notifications=user_profile. enable_offline_email_notifications, pm_content_in_desktop_notifications=user_profile. pm_content_in_desktop_notifications, enable_offline_push_notifications=user_profile. enable_offline_push_notifications, enable_online_push_notifications=user_profile. enable_online_push_notifications, twenty_four_hour_time=register_ret['twenty_four_hour_time'], enable_digest_emails=user_profile.enable_digest_emails, event_queue_id=register_ret['queue_id'], last_event_id=register_ret['last_event_id'], max_message_id=register_ret['max_message_id'], unread_count=approximate_unread_count(user_profile), furthest_read_time=sent_time_in_epoch_seconds(latest_read), save_stacktraces=settings.SAVE_FRONTEND_STACKTRACES, alert_words=register_ret['alert_words'], attachments=register_ret['attachments'], muted_topics=register_ret['muted_topics'], realm_filters=register_ret['realm_filters'], realm_default_streams=register_ret['realm_default_streams'], is_admin=user_profile.is_realm_admin, can_create_streams=user_profile.can_create_streams(), name_changes_disabled=name_changes_disabled(user_profile.realm), has_mobile_devices=num_push_devices_for_user(user_profile) > 0, autoscroll_forever=user_profile.autoscroll_forever, default_desktop_notifications=user_profile. default_desktop_notifications, avatar_url=avatar_url(user_profile), avatar_url_medium=avatar_url(user_profile, medium=True), avatar_source=user_profile.avatar_source, mandatory_topics=user_profile.realm.mandatory_topics, show_digest_email=user_profile.realm.show_digest_email, presence_disabled=user_profile.realm.presence_disabled, is_zephyr_mirror_realm=user_profile.realm.is_zephyr_mirror_realm, ) if narrow_stream is not None: # In narrow_stream context, initial pointer is just latest message recipient = get_recipient(Recipient.STREAM, narrow_stream.id) try: initial_pointer = Message.objects.filter( recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -1 page_params["narrow_stream"] = narrow_stream.name if narrow_topic is not None: page_params["narrow_topic"] = narrow_topic page_params["narrow"] = [ dict(operator=term[0], operand=term[1]) for term in narrow ] page_params["max_message_id"] = initial_pointer page_params["initial_pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False product_name = "Zulip" page_params['product_name'] = product_name request._log_data['extra'] = "[%s]" % (register_ret["queue_id"], ) response = render_to_response('zerver/index.html', { 'user_profile': user_profile, 'page_params': simplejson.encoder.JSONEncoderForHTML().encode(page_params), 'nofontface': is_buggy_ua(request.META.get("HTTP_USER_AGENT", "Unspecified")), 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'show_invites': show_invites, 'is_admin': user_profile.is_realm_admin, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, 'product_name': product_name }, request=request) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[str], user_profile: Optional[UserProfile], full_name: str='', invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None, is_signup: bool=False, redirect_to: str='', multiuse_object_key: str='') -> HttpResponse: """Given a successful authentication showing the user controls given email address (remote_username) and potentially a UserProfile object (if the user already has a Zulip account), redirect the browser to the appropriate place: * The logged-in app if the user already has a Zulip account and is trying to login, potentially to an initial narrow or page that had been saved in the `redirect_to` parameter. * The registration form if is_signup was set (i.e. the user is trying to create a Zulip account) * A special `confirm_continue_registration.html` "do you want to register or try another account" if the user doesn't have a Zulip account but is_signup is False (i.e. the user tried to login and then did social authentication selecting an email address that does not have a Zulip account in this organization). * A zulip:// URL to send control back to the mobile apps if they are doing authentication using the mobile_flow_otp flow. """ email = remote_user_to_email(remote_username) if user_profile is None or user_profile.is_mirror_dummy: # We have verified the user controls an email address, but # there's no associated Zulip user account. Consider sending # the request to registration. return maybe_send_to_registration(request, email, full_name, password_required=False, is_signup=is_signup, multiuse_object_key=multiuse_object_key) # Otherwise, the user has successfully authenticated to an # account, and we need to do the right thing depending whether # or not they're using the mobile OTP flow or want a browser session. if mobile_flow_otp is not None: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. api_key = get_api_key(user_profile) params = { 'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp), 'email': email, 'realm': user_profile.realm.uri, } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params) # Since we are returning an API key instead of going through # the Django login() function (which creates a browser # session, etc.), the "new login" signal handler (which # triggers an email notification new logins) will not run # automatically. So we call it manually here. # # Arguably, sending a fake 'user_logged_in' signal would be a better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email return response do_login(request, user_profile) redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri) return HttpResponseRedirect(redirect_to)
def get_events_internal(request: HttpRequest, handler: BaseHandler, user_profile_id: int=REQ()) -> Union[HttpResponse, _RespondAsynchronously]: user_profile = get_user_profile_by_id(user_profile_id) request._email = user_profile.email process_client(request, user_profile, client_name="internal") return get_events_backend(request, user_profile, handler)
def login_or_register_remote_user( request: HttpRequest, remote_username: str, user_profile: Optional[UserProfile], full_name: str = '', mobile_flow_otp: Optional[str] = None, is_signup: bool = False, redirect_to: str = '', multiuse_object_key: str = '') -> HttpResponse: """Given a successful authentication showing the user controls given email address (remote_username) and potentially a UserProfile object (if the user already has a Zulip account), redirect the browser to the appropriate place: * The logged-in app if the user already has a Zulip account and is trying to login, potentially to an initial narrow or page that had been saved in the `redirect_to` parameter. * The registration form if is_signup was set (i.e. the user is trying to create a Zulip account) * A special `confirm_continue_registration.html` "do you want to register or try another account" if the user doesn't have a Zulip account but is_signup is False (i.e. the user tried to login and then did social authentication selecting an email address that does not have a Zulip account in this organization). * A zulip:// URL to send control back to the mobile apps if they are doing authentication using the mobile_flow_otp flow. """ email = remote_user_to_email(remote_username) if user_profile is None or user_profile.is_mirror_dummy: # We have verified the user controls an email address, but # there's no associated Zulip user account. Consider sending # the request to registration. return maybe_send_to_registration( request, email, full_name, password_required=False, is_signup=is_signup, multiuse_object_key=multiuse_object_key) # Otherwise, the user has successfully authenticated to an # account, and we need to do the right thing depending whether # or not they're using the mobile OTP flow or want a browser session. if mobile_flow_otp is not None: # For the mobile Oauth flow, we send the API key and other # necessary details in a redirect to a zulip:// URI scheme. api_key = get_api_key(user_profile) params = { 'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp), 'email': email, 'realm': user_profile.realm.uri, } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) response['Location'] = 'zulip://login?' + urllib.parse.urlencode( params) # Since we are returning an API key instead of going through # the Django login() function (which creates a browser # session, etc.), the "new login" signal handler (which # triggers an email notification new logins) will not run # automatically. So we call it manually here. # # Arguably, sending a fake 'user_logged_in' signal would be a better approach: # user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile) email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile) # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) request._email = user_profile.email return response do_login(request, user_profile) redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri) return HttpResponseRedirect(redirect_to)