Example #1
0
def principal_to_user_profile(agent, principal):
    principal_doesnt_exist = False
    try:
        principal_user_profile = get_user_profile_by_email(principal)
    except UserProfile.DoesNotExist:
        principal_doesnt_exist = True

    if (principal_doesnt_exist or agent.realm != principal_user_profile.realm):
        # We have to make sure we don't leak information about which users
        # are registered for Zulip in a different realm.  We could do
        # something a little more clever and check the domain part of the
        # principal to maybe give a better error message
        raise PrincipalError(principal)

    return principal_user_profile
Example #2
0
def principal_to_user_profile(agent, principal):
    principal_doesnt_exist = False
    try:
        principal_user_profile = get_user_profile_by_email(principal)
    except UserProfile.DoesNotExist:
        principal_doesnt_exist = True

    if (principal_doesnt_exist
        or agent.realm != principal_user_profile.realm):
        # We have to make sure we don't leak information about which users
        # are registered for Zulip in a different realm.  We could do
        # something a little more clever and check the domain part of the
        # principal to maybe give a better error message
        raise PrincipalError(principal)

    return principal_user_profile
Example #3
0
def accounts_register(request):
    # type: (HttpRequest) -> HttpResponse
    key = request.POST['key']
    confirmation = Confirmation.objects.get(confirmation_key=key)
    prereg_user = confirmation.content_object
    email = prereg_user.email
    realm_creation = prereg_user.realm_creation
    try:
        existing_user_profile = get_user_profile_by_email(email)
    except UserProfile.DoesNotExist:
        existing_user_profile = None

    validators.validate_email(email)
    # If OPEN_REALM_CREATION is enabled all user sign ups should go through the
    # special URL with domain name so that REALM can be identified if multiple realms exist
    unique_open_realm = get_unique_open_realm()
    if unique_open_realm is not None:
        realm = unique_open_realm
    elif prereg_user.referred_by:
        # If someone invited you, you are joining their realm regardless
        # of your e-mail address.
        realm = prereg_user.referred_by.realm
    elif prereg_user.realm:
        # You have a realm set, even though nobody referred you. This
        # happens if you sign up through a special URL for an open realm.
        realm = prereg_user.realm
    elif realm_creation:
        # For creating a new realm, there is no existing realm or domain
        realm = None
    elif settings.REALMS_HAVE_SUBDOMAINS:
        realm = get_realm(get_subdomain(request))
    else:
        realm = get_realm_by_email_domain(email)

    if realm and not email_allowed_for_realm(email, realm):
        return render(request,
                      "zerver/closed_realm.html",
                      context={"closed_domain_name": realm.name})

    if realm and realm.deactivated:
        # The user is trying to register for a deactivated realm. Advise them to
        # contact support.
        return render(request,
                      "zerver/deactivated.html",
                      context={
                          "deactivated_domain_name": realm.name,
                          "zulip_administrator": settings.ZULIP_ADMINISTRATOR
                      })

    try:
        if existing_user_profile is not None and existing_user_profile.is_mirror_dummy:
            # Mirror dummy users to be activated must be inactive
            is_inactive(email)
        else:
            # Other users should not already exist at all.
            user_email_is_unique(email)
    except ValidationError:
        return HttpResponseRedirect(
            reverse('django.contrib.auth.views.login') + '?email=' +
            urllib.parse.quote_plus(email))

    name_validated = False
    full_name = None

    if request.POST.get('from_confirmation'):
        try:
            del request.session['authenticated_full_name']
        except KeyError:
            pass
        if realm is not None and realm.is_zephyr_mirror_realm:
            # For MIT users, we can get an authoritative name from Hesiod.
            # Technically we should check that this is actually an MIT
            # realm, but we can cross that bridge if we ever get a non-MIT
            # zephyr mirroring realm.
            hesiod_name = compute_mit_user_fullname(email)
            form = RegistrationForm(
                initial={
                    'full_name': hesiod_name if "@" not in hesiod_name else ""
                })
            name_validated = True
        elif settings.POPULATE_PROFILE_VIA_LDAP:
            for backend in get_backends():
                if isinstance(backend, LDAPBackend):
                    ldap_attrs = _LDAPUser(
                        backend, backend.django_to_ldap_username(email)).attrs
                    try:
                        ldap_full_name = ldap_attrs[
                            settings.AUTH_LDAP_USER_ATTR_MAP['full_name']][0]
                        request.session[
                            'authenticated_full_name'] = ldap_full_name
                        name_validated = True
                        # We don't use initial= here, because if the form is
                        # complete (that is, no additional fields need to be
                        # filled out by the user) we want the form to validate,
                        # so they can be directly registered without having to
                        # go through this interstitial.
                        form = RegistrationForm({'full_name': ldap_full_name})
                        # FIXME: This will result in the user getting
                        # validation errors if they have to enter a password.
                        # Not relevant for ONLY_SSO, though.
                        break
                    except TypeError:
                        # Let the user fill out a name and/or try another backend
                        form = RegistrationForm()
        elif 'full_name' in request.POST:
            form = RegistrationForm(
                initial={'full_name': request.POST.get('full_name')})
        else:
            form = RegistrationForm()
    else:
        postdata = request.POST.copy()
        if name_changes_disabled(realm):
            # If we populate profile information via LDAP and we have a
            # verified name from you on file, use that. Otherwise, fall
            # back to the full name in the request.
            try:
                postdata.update(
                    {'full_name': request.session['authenticated_full_name']})
                name_validated = True
            except KeyError:
                pass
        form = RegistrationForm(postdata)
        if not password_auth_enabled(realm):
            form['password'].field.required = False

    if form.is_valid():
        if password_auth_enabled(realm):
            password = form.cleaned_data['password']
        else:
            # SSO users don't need no passwords
            password = None

        if realm_creation:
            string_id = form.cleaned_data['realm_subdomain']
            realm_name = form.cleaned_data['realm_name']
            org_type = int(form.cleaned_data['realm_org_type'])
            realm = do_create_realm(string_id, realm_name,
                                    org_type=org_type)[0]

            set_default_streams(realm, settings.DEFAULT_NEW_REALM_STREAMS)

        full_name = form.cleaned_data['full_name']
        short_name = email_to_username(email)
        first_in_realm = len(
            UserProfile.objects.filter(realm=realm, is_bot=False)) == 0

        # FIXME: sanitize email addresses and fullname
        if existing_user_profile is not None and existing_user_profile.is_mirror_dummy:
            user_profile = existing_user_profile
            do_activate_user(user_profile)
            do_change_password(user_profile, password)
            do_change_full_name(user_profile, full_name)
        else:
            user_profile = do_create_user(
                email,
                password,
                realm,
                full_name,
                short_name,
                prereg_user=prereg_user,
                tos_version=settings.TOS_VERSION,
                newsletter_data={"IP": request.META['REMOTE_ADDR']})

        if first_in_realm:
            do_change_is_admin(user_profile, True)

        if realm_creation and settings.REALMS_HAVE_SUBDOMAINS:
            # Because for realm creation, registration happens on the
            # root domain, we need to log them into the subdomain for
            # their new realm.
            return redirect_and_log_into_subdomain(realm, full_name, email)

        # This dummy_backend check below confirms the user is
        # authenticating to the correct subdomain.
        return_data = {}  # type: Dict[str, bool]
        auth_result = authenticate(username=user_profile.email,
                                   realm_subdomain=realm.subdomain,
                                   return_data=return_data,
                                   use_dummy_backend=True)
        if return_data.get('invalid_subdomain'):
            # By construction, this should never happen.
            logging.error("Subdomain mismatch in registration %s: %s" % (
                realm.subdomain,
                user_profile.email,
            ))
            return redirect('/')
        login(request, auth_result)
        return HttpResponseRedirect(realm.uri +
                                    reverse('zerver.views.home.home'))

    return render(
        request,
        'zerver/register.html',
        context={
            'form': form,
            'email': email,
            'key': key,
            'full_name': request.session.get('authenticated_full_name', None),
            'lock_name': name_validated and name_changes_disabled(realm),
            # password_auth_enabled is normally set via our context processor,
            # but for the registration form, there is no logged in user yet, so
            # we have to set it here.
            'creating_new_team': realm_creation,
            'realms_have_subdomains': settings.REALMS_HAVE_SUBDOMAINS,
            'password_auth_enabled': password_auth_enabled(realm),
            'MAX_REALM_NAME_LENGTH': str(Realm.MAX_REALM_NAME_LENGTH),
            'MAX_NAME_LENGTH': str(UserProfile.MAX_NAME_LENGTH),
            'MAX_PASSWORD_LENGTH': str(form.MAX_PASSWORD_LENGTH),
            'MAX_REALM_SUBDOMAIN_LENGTH': str(Realm.MAX_REALM_SUBDOMAIN_LENGTH)
        })
Example #4
0
def add_subscriptions_backend(
    request,
    user_profile,
    streams_raw=REQ("subscriptions",
                    validator=check_list(check_dict([('name', check_string)
                                                     ]))),
    invite_only=REQ(validator=check_bool, default=False),
    announce=REQ(validator=check_bool, default=False),
    principals=REQ(validator=check_list(check_string), default=[]),
    authorization_errors_fatal=REQ(validator=check_bool, default=True)):
    # type: (HttpRequest, UserProfile, Iterable[Mapping[str, Text]], bool, bool, List[Text], bool) -> HttpResponse
    stream_dicts = []
    for stream_dict in streams_raw:
        stream_dict_copy = {}  # type: Dict[str, Any]
        for field in stream_dict:
            stream_dict_copy[field] = stream_dict[field]
        # Strip the stream name here.
        stream_dict_copy['name'] = stream_dict_copy['name'].strip()
        stream_dict_copy["invite_only"] = invite_only
        stream_dicts.append(stream_dict_copy)

    # Validation of the streams arguments, including enforcement of
    # can_create_streams policy and check_stream_name policy is inside
    # list_to_streams.
    existing_streams, created_streams = \
        list_to_streams(stream_dicts, user_profile, autocreate=True)
    authorized_streams, unauthorized_streams = \
        filter_stream_authorization(user_profile, existing_streams)
    if len(unauthorized_streams) > 0 and authorization_errors_fatal:
        return json_error(
            _("Unable to access stream (%s).") % unauthorized_streams[0].name)
    # Newly created streams are also authorized for the creator
    streams = authorized_streams + created_streams

    if len(principals) > 0:
        if user_profile.realm.is_zephyr_mirror_realm and not all(
                stream.invite_only for stream in streams):
            return json_error(
                _("You can only invite other Zephyr mirroring users to invite-only streams."
                  ))
        subscribers = set(
            principal_to_user_profile(user_profile, principal)
            for principal in principals)
    else:
        subscribers = set([user_profile])

    (subscribed,
     already_subscribed) = bulk_add_subscriptions(streams, subscribers)

    result = dict(subscribed=defaultdict(list),
                  already_subscribed=defaultdict(list))  # type: Dict[str, Any]
    for (subscriber, stream) in subscribed:
        result["subscribed"][subscriber.email].append(stream.name)
    for (subscriber, stream) in already_subscribed:
        result["already_subscribed"][subscriber.email].append(stream.name)

    private_streams = dict(
        (stream.name, stream.invite_only) for stream in streams)
    bots = dict(
        (subscriber.email, subscriber.is_bot) for subscriber in subscribers)

    # Inform the user if someone else subscribed them to stuff,
    # or if a new stream was created with the "announce" option.
    notifications = []
    if len(principals) > 0 and result["subscribed"]:
        for email, subscriptions in six.iteritems(result["subscribed"]):
            if email == user_profile.email:
                # Don't send a Zulip if you invited yourself.
                continue
            if bots[email]:
                # Don't send invitation Zulips to bots
                continue

            if len(subscriptions) == 1:
                msg = ("Hi there!  We thought you'd like to know that %s just "
                       "subscribed you to the%s stream #**%s**." % (
                           user_profile.full_name,
                           " **invite-only**"
                           if private_streams[subscriptions[0]] else "",
                           subscriptions[0],
                       ))
            else:
                msg = ("Hi there!  We thought you'd like to know that %s just "
                       "subscribed you to the following streams: \n\n" %
                       (user_profile.full_name, ))
                for stream in subscriptions:
                    msg += "* #**%s**%s\n" % (stream, " (**invite-only**)" if
                                              private_streams[stream] else "")

            if len([s for s in subscriptions if not private_streams[s]]) > 0:
                msg += "\nYou can see historical content on a non-invite-only stream by narrowing to it."

            sender = get_user_profile_by_email(settings.NOTIFICATION_BOT)
            notifications.append(
                internal_prep_private_message(realm=user_profile.realm,
                                              sender=sender,
                                              recipient_email=email,
                                              content=msg))

    if announce and len(created_streams) > 0:
        notifications_stream = user_profile.realm.notifications_stream  # type: Optional[Stream]
        if notifications_stream is not None:
            if len(created_streams) > 1:
                stream_msg = "the following streams: %s" % (", ".join(
                    '#**%s**' % s.name for s in created_streams))
            else:
                stream_msg = "a new stream #**%s**." % created_streams[0].name
            msg = ("%s just created %s" % (user_profile.full_name, stream_msg))

            sender = get_user_profile_by_email(settings.NOTIFICATION_BOT)
            stream_name = notifications_stream.name
            topic = 'Streams'

            notifications.append(
                internal_prep_stream_message(realm=user_profile.realm,
                                             sender=sender,
                                             stream_name=stream_name,
                                             topic=topic,
                                             content=msg))

        else:
            msg = ("Hi there!  %s just created a new stream #**%s**." %
                   (user_profile.full_name, created_streams[0].name))

            sender = get_user_profile_by_email(settings.NOTIFICATION_BOT)
            for realm_user_dict in get_active_user_dicts_in_realm(
                    user_profile.realm):
                # Don't announce to yourself or to people you explicitly added
                # (who will get the notification above instead).
                if realm_user_dict['email'] in principals or realm_user_dict[
                        'email'] == user_profile.email:
                    continue

                recipient_email = realm_user_dict['email']

                notifications.append(
                    internal_prep_private_message(
                        realm=user_profile.realm,
                        sender=sender,
                        recipient_email=recipient_email,
                        content=msg))

    if not user_profile.realm.is_zephyr_mirror_realm:
        for stream in created_streams:
            notifications.append(prep_stream_welcome_message(stream))

    if len(notifications) > 0:
        do_send_messages(notifications)

    result["subscribed"] = dict(result["subscribed"])
    result["already_subscribed"] = dict(result["already_subscribed"])
    if not authorization_errors_fatal:
        result["unauthorized"] = [
            stream.name for stream in unauthorized_streams
        ]
    return json_success(result)
Example #5
0
def add_subscriptions_backend(
    request,
    user_profile,
    streams_raw=REQ("subscriptions",
                    validator=check_list(check_dict([('name', check_string)
                                                     ]))),
    invite_only=REQ(validator=check_bool, default=False),
    announce=REQ(validator=check_bool, default=False),
    principals=REQ(validator=check_list(check_string), default=[]),
    authorization_errors_fatal=REQ(validator=check_bool, default=True)):
    # type: (HttpRequest, UserProfile, Iterable[Mapping[str, Text]], bool, bool, List[Text], bool) -> HttpResponse
    stream_dicts = []
    for stream_dict in streams_raw:
        stream_dict_copy = {}  # type: Dict[str, Any]
        for field in stream_dict:
            stream_dict_copy[field] = stream_dict[field]
        # Strip the stream name here.
        stream_dict_copy['name'] = stream_dict_copy['name'].strip()
        stream_dict_copy["invite_only"] = invite_only
        stream_dicts.append(stream_dict_copy)

    # Validation of the streams arguments, including enforcement of
    # can_create_streams policy and check_stream_name policy is inside
    # list_to_streams.
    existing_streams, created_streams = \
        list_to_streams(stream_dicts, user_profile, autocreate=True)
    authorized_streams, unauthorized_streams = \
        filter_stream_authorization(user_profile, existing_streams)
    if len(unauthorized_streams) > 0 and authorization_errors_fatal:
        return json_error(
            _("Unable to access stream (%s).") % unauthorized_streams[0].name)
    # Newly created streams are also authorized for the creator
    streams = authorized_streams + created_streams

    if len(principals) > 0:
        if user_profile.realm.is_zephyr_mirror_realm and not all(
                stream.invite_only for stream in streams):
            return json_error(
                _("You can only invite other Zephyr mirroring users to invite-only streams."
                  ))
        subscribers = set(
            principal_to_user_profile(user_profile, principal)
            for principal in principals)
    else:
        subscribers = set([user_profile])

    (subscribed,
     already_subscribed) = bulk_add_subscriptions(streams, subscribers)

    result = dict(subscribed=defaultdict(list),
                  already_subscribed=defaultdict(list))  # type: Dict[str, Any]
    for (subscriber, stream) in subscribed:
        result["subscribed"][subscriber.email].append(stream.name)
    for (subscriber, stream) in already_subscribed:
        result["already_subscribed"][subscriber.email].append(stream.name)

    bots = dict(
        (subscriber.email, subscriber.is_bot) for subscriber in subscribers)

    newly_created_stream_names = {stream.name for stream in created_streams}
    private_stream_names = {
        stream.name
        for stream in streams if stream.invite_only
    }

    # Inform the user if someone else subscribed them to stuff,
    # or if a new stream was created with the "announce" option.
    notifications = []
    if len(principals) > 0 and result["subscribed"]:
        for email, subscribed_stream_names in six.iteritems(
                result["subscribed"]):
            if email == user_profile.email:
                # Don't send a Zulip if you invited yourself.
                continue
            if bots[email]:
                # Don't send invitation Zulips to bots
                continue

            # For each user, we notify them about newly subscribed streams, except for
            # streams that were newly created.
            notify_stream_names = set(
                subscribed_stream_names) - newly_created_stream_names

            if not notify_stream_names:
                continue

            msg = you_were_just_subscribed_message(
                acting_user=user_profile,
                stream_names=notify_stream_names,
                private_stream_names=private_stream_names)

            sender = get_user_profile_by_email(settings.NOTIFICATION_BOT)
            notifications.append(
                internal_prep_private_message(realm=user_profile.realm,
                                              sender=sender,
                                              recipient_email=email,
                                              content=msg))

    if announce and len(created_streams) > 0:
        notifications_stream = user_profile.realm.notifications_stream  # type: Optional[Stream]
        if notifications_stream is not None:
            if len(created_streams) > 1:
                stream_msg = "the following streams: %s" % (", ".join(
                    '#**%s**' % s.name for s in created_streams))
            else:
                stream_msg = "a new stream #**%s**." % created_streams[0].name
            msg = ("%s just created %s" % (user_profile.full_name, stream_msg))

            sender = get_user_profile_by_email(settings.NOTIFICATION_BOT)
            stream_name = notifications_stream.name
            topic = 'Streams'

            notifications.append(
                internal_prep_stream_message(realm=user_profile.realm,
                                             sender=sender,
                                             stream_name=stream_name,
                                             topic=topic,
                                             content=msg))

    if not user_profile.realm.is_zephyr_mirror_realm:
        for stream in created_streams:
            notifications.append(prep_stream_welcome_message(stream))

    if len(notifications) > 0:
        do_send_messages(notifications)

    result["subscribed"] = dict(result["subscribed"])
    result["already_subscribed"] = dict(result["already_subscribed"])
    if not authorization_errors_fatal:
        result["unauthorized"] = [
            stream.name for stream in unauthorized_streams
        ]
    return json_success(result)