def test_get_user(self) -> None:
        mit_realm = get_realm("zephyr")
        user_profile = self.example_user("hamlet")
        email = user_profile.delivery_email

        self.assertEqual(self.command.get_user(email, self.zulip_realm),
                         user_profile)
        self.assertEqual(self.command.get_user(email, None), user_profile)

        error_message = f"The realm '{mit_realm}' does not contain a user with email"
        with self.assertRaisesRegex(CommandError, error_message):
            self.command.get_user(email, mit_realm)

        with self.assertRaisesRegex(
                CommandError, "server does not contain a user with email"):
            self.command.get_user("*****@*****.**", None)

        do_create_user(email,
                       "password",
                       mit_realm,
                       "full_name",
                       acting_user=None)

        with self.assertRaisesRegex(
                CommandError,
                "server contains multiple users with that email"):
            self.command.get_user(email, None)
Esempio n. 2
0
    def handle(self, *args: Any, **options: str) -> None:
        realm_name = options["realm_name"]
        string_id = options["string_id"]

        create_user_params = self.get_create_user_params(options)

        try:
            realm = do_create_realm(string_id=string_id, name=realm_name)
        except AssertionError as e:
            raise CommandError(str(e))

        do_create_user(
            create_user_params.email,
            create_user_params.password,
            realm,
            create_user_params.full_name,
            # Explicitly set tos_version=None. For servers that
            # have configured Terms of Service, this means that
            # users created via this mechanism will be prompted to
            # accept the Terms of Service on first login.
            role=UserProfile.ROLE_REALM_OWNER,
            realm_creation=True,
            tos_version=None,
            acting_user=None,
        )
Esempio n. 3
0
    def test_no_email_digest_for_bots(self) -> None:
        RealmAuditLog.objects.all().delete()

        cutoff = timezone_now() - datetime.timedelta(days=5)

        realm = get_realm("zulip")
        realm.digest_emails_enabled = True
        realm.save()

        bot = do_create_user(
            "*****@*****.**",
            "password",
            realm,
            "some_bot",
            bot_type=UserProfile.DEFAULT_BOT,
            acting_user=None,
        )

        # Check that bots are not sent emails
        with mock.patch(
                "zerver.lib.digest.queue_digest_user_ids") as queue_mock:
            _enqueue_emails_for_realm(realm, cutoff)

        num_queued_users = len(queue_mock.call_args[0][0])
        assert num_queued_users >= 5

        for arg in queue_mock.call_args_list:
            user_ids = arg[0][0]
            for user_id in user_ids:
                self.assertNotEqual(user_id, bot.id)
Esempio n. 4
0
 def test_upload_already_existed_emoji_in_check_add_realm_emoji(
         self) -> None:
     realm_1 = do_create_realm("test_realm", "test_realm")
     emoji_author = do_create_user("*****@*****.**",
                                   password="******",
                                   realm=realm_1,
                                   full_name="abc",
                                   acting_user=None)
     emoji_name = "emoji_test"
     with get_test_image_file("img.png") as img_file:
         # Because we want to verify the IntegrityError handling
         # logic in check_add_realm_emoji rather than the primary
         # check in upload_emoji, we need to make this request via
         # that helper rather than via the API.
         check_add_realm_emoji(realm=emoji_author.realm,
                               name=emoji_name,
                               author=emoji_author,
                               image_file=img_file)
         with self.assertRaises(JsonableError):
             check_add_realm_emoji(
                 realm=emoji_author.realm,
                 name=emoji_name,
                 author=emoji_author,
                 image_file=img_file,
             )
def deactivate_user() -> Dict[str, object]:
    user_profile = do_create_user(
        email="*****@*****.**",
        password=None,
        full_name="test_user",
        realm=get_realm("zulip"),
        acting_user=None,
    )
    return {"user_id": user_profile.id}
Esempio n. 6
0
    def create_non_active_user(self, realm: Realm, email: str, name: str) -> UserProfile:
        user = do_create_user(
            email=email, password="******", realm=realm, full_name=name, acting_user=None
        )

        # Doing a full-stack deactivation would be expensive here,
        # and we really only need to flip the flag to get a valid
        # test.
        change_user_is_active(user, False)
        return user
Esempio n. 7
0
def create_user_backend(
        request: HttpRequest,
        user_profile: UserProfile,
        email: str = REQ(),
        password: str = REQ(),
        full_name_raw: str = REQ("full_name"),
) -> HttpResponse:
    if not user_profile.can_create_users:
        raise JsonableError(_("User not authorized for this query"))

    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({"full_name": full_name, "email": email})
    if not form.is_valid():
        raise JsonableError(_("Bad name or username"))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    try:
        email_allowed_for_realm(email, user_profile.realm)
    except DomainNotAllowedForRealmError:
        raise JsonableError(
            _("Email '{email}' not allowed in this organization").format(
                email=email, ))
    except DisposableEmailError:
        raise JsonableError(
            _("Disposable email addresses are not allowed in this organization"
              ))
    except EmailContainsPlusError:
        raise JsonableError(_("Email addresses containing + are not allowed."))

    try:
        get_user_by_delivery_email(email, user_profile.realm)
        raise JsonableError(_("Email '{}' already in use").format(email))
    except UserProfile.DoesNotExist:
        pass

    if not check_password_strength(password):
        raise JsonableError(PASSWORD_TOO_WEAK_ERROR)

    target_user = do_create_user(
        email,
        password,
        realm,
        full_name,
        # Explicitly set tos_version=None. For servers that have
        # configured Terms of Service, this means that users created
        # via this mechanism will be prompted to accept the Terms of
        # Service on first login.
        tos_version=None,
        acting_user=user_profile,
    )
    return json_success(request, data={"user_id": target_user.id})
Esempio n. 8
0
 def create_bot(self, owner: UserProfile, bot_email: str, bot_name: str) -> UserProfile:
     user = do_create_user(
         email=bot_email,
         password="******",
         realm=owner.realm,
         full_name=bot_name,
         bot_type=UserProfile.DEFAULT_BOT,
         bot_owner=owner,
         acting_user=None,
     )
     return user
Esempio n. 9
0
    def handle(self, *args: Any, **options: Any) -> None:
        realm = self.get_realm(options)
        assert realm is not None  # Should be ensured by parser

        create_user_params = self.get_create_user_params(options)

        try:
            do_create_user(
                create_user_params.email,
                create_user_params.password,
                realm,
                create_user_params.full_name,
                # Explicitly set tos_version=None. For servers that
                # have configured Terms of Service, this means that
                # users created via this mechanism will be prompted to
                # accept the Terms of Service on first login.
                tos_version=None,
                acting_user=None,
            )
        except IntegrityError:
            raise CommandError("User already exists.")
Esempio n. 10
0
    def _get_outgoing_bot(self) -> UserProfile:
        outgoing_bot = do_create_user(
            email="*****@*****.**",
            password="******",
            realm=get_realm("zulip"),
            full_name="BarBot",
            bot_type=UserProfile.OUTGOING_WEBHOOK_BOT,
            bot_owner=self.example_user("cordelia"),
            acting_user=None,
        )

        return outgoing_bot
Esempio n. 11
0
 def setUp(self) -> None:
     super().setUp()
     self.user_profile = self.example_user("othello")
     self.bot_profile = do_create_user(
         email="*****@*****.**",
         password="******",
         realm=get_realm("zulip"),
         full_name="FooBot",
         bot_type=UserProfile.OUTGOING_WEBHOOK_BOT,
         bot_owner=self.user_profile,
         acting_user=None,
     )
     self.second_bot_profile = do_create_user(
         email="*****@*****.**",
         password="******",
         realm=get_realm("zulip"),
         full_name="BarBot",
         bot_type=UserProfile.OUTGOING_WEBHOOK_BOT,
         bot_owner=self.user_profile,
         acting_user=None,
     )
Esempio n. 12
0
 def setUp(self) -> None:
     super().setUp()
     self.user_profile = self.example_user("othello")
     self.bot_profile = do_create_user(
         email="*****@*****.**",
         password="******",
         realm=get_realm("zulip"),
         full_name="EmbeddedBo1",
         bot_type=UserProfile.EMBEDDED_BOT,
         bot_owner=self.user_profile,
         acting_user=None,
     )
     self.second_bot_profile = do_create_user(
         email="*****@*****.**",
         password="******",
         realm=get_realm("zulip"),
         full_name="EmbeddedBot2",
         bot_type=UserProfile.EMBEDDED_BOT,
         bot_owner=self.user_profile,
         acting_user=None,
     )
Esempio n. 13
0
    def test_check_admin_different_realm_emoji(self) -> None:
        # Test that two different realm emojis in two different realms but
        # having same name can be administered independently.
        realm_1 = do_create_realm("test_realm", "test_realm")
        emoji_author_1 = do_create_user("*****@*****.**",
                                        password="******",
                                        realm=realm_1,
                                        full_name="abc",
                                        acting_user=None)
        self.create_test_emoji("test_emoji", emoji_author_1)

        emoji_author_2 = self.example_user("othello")
        self.create_test_emoji("test_emoji", emoji_author_2)
        self.login_user(emoji_author_2)
        result = self.client_delete("/json/realm/emoji/test_emoji")
        self.assert_json_success(result)
def deactivate_own_user() -> Dict[str, object]:
    test_user_email = "*****@*****.**"
    deactivate_test_user = do_create_user(
        test_user_email,
        "secret",
        get_realm("zulip"),
        "Mr. Delete",
        role=200,
        acting_user=None,
    )
    realm = get_realm("zulip")
    test_user = get_user(test_user_email, realm)
    test_user_api_key = get_api_key(test_user)
    # change authentication line to allow test_client to delete itself.
    AUTHENTICATION_LINE[
        0] = f"{deactivate_test_user.email}:{test_user_api_key}"
    return {}
Esempio n. 15
0
 def test_user_activation(self) -> None:
     realm = get_realm("zulip")
     now = timezone_now()
     user = do_create_user("email",
                           "password",
                           realm,
                           "full_name",
                           acting_user=None)
     do_deactivate_user(user, acting_user=user)
     do_activate_mirror_dummy_user(user, acting_user=user)
     do_deactivate_user(user, acting_user=user)
     do_reactivate_user(user, acting_user=user)
     self.assertEqual(
         RealmAuditLog.objects.filter(event_time__gte=now).count(), 6)
     event_types = list(
         RealmAuditLog.objects.filter(
             realm=realm,
             acting_user=user,
             modified_user=user,
             modified_stream=None,
             event_time__gte=now,
             event_time__lte=now + timedelta(minutes=60),
         ).order_by("event_time").values_list("event_type", flat=True))
     self.assertEqual(
         event_types,
         [
             RealmAuditLog.USER_CREATED,
             RealmAuditLog.USER_DEACTIVATED,
             RealmAuditLog.USER_ACTIVATED,
             RealmAuditLog.USER_DEACTIVATED,
             RealmAuditLog.USER_REACTIVATED,
         ],
     )
     for event in RealmAuditLog.objects.filter(
             realm=realm,
             acting_user=user,
             modified_user=user,
             modified_stream=None,
             event_time__gte=now,
             event_time__lte=now + timedelta(minutes=60),
     ):
         extra_data = orjson.loads(assert_is_not_none(event.extra_data))
         self.check_role_count_schema(extra_data[RealmAuditLog.ROLE_COUNT])
         self.assertNotIn(RealmAuditLog.OLD_VALUE, extra_data)
Esempio n. 16
0
    def test_multiple_services(self) -> None:
        bot_owner = self.example_user("othello")

        bot = do_create_user(
            bot_owner=bot_owner,
            bot_type=UserProfile.OUTGOING_WEBHOOK_BOT,
            full_name="Outgoing Webhook Bot",
            email="whatever",
            realm=bot_owner.realm,
            password=None,
            acting_user=None,
        )

        add_service(
            "weather",
            user_profile=bot,
            interface=Service.GENERIC,
            base_url="https://weather.example.com/",
            token="weather_token",
        )

        add_service(
            "qotd",
            user_profile=bot,
            interface=Service.GENERIC,
            base_url="https://qotd.example.com/",
            token="qotd_token",
        )

        sender = self.example_user("hamlet")

        responses.add(
            responses.POST,
            "https://weather.example.com/",
            json={},
        )
        responses.add(
            responses.POST,
            "https://qotd.example.com/",
            json={},
        )
        with self.assertLogs(level="INFO") as logs:
            self.send_personal_message(
                sender,
                bot,
                content="some content",
            )
        self.assert_length(logs.output, 2)
        self.assertIn(f"Outgoing webhook request from {bot.id}@zulip took ",
                      logs.output[0])
        self.assertIn(f"Outgoing webhook request from {bot.id}@zulip took ",
                      logs.output[1])

        self.assert_length(responses.calls, 2)

        calls_by_url = {
            call.request.url: orjson.loads(call.request.body or b"")
            for call in responses.calls
        }
        weather_req = calls_by_url["https://weather.example.com/"]
        self.assertEqual(weather_req["token"], "weather_token")
        self.assertEqual(weather_req["message"]["content"], "some content")
        self.assertEqual(weather_req["message"]["sender_id"], sender.id)

        qotd_req = calls_by_url["https://qotd.example.com/"]
        self.assertEqual(qotd_req["token"], "qotd_token")
        self.assertEqual(qotd_req["message"]["content"], "some content")
        self.assertEqual(qotd_req["message"]["sender_id"], sender.id)
Esempio n. 17
0
    def save(self) -> None:
        """
        This method is called at the end of operations modifying a user,
        and is responsible for actually applying the requested changes,
        writing them to the database.
        """
        realm = RequestNotes.get_notes(self._request).realm
        assert realm is not None

        email_new_value = getattr(self, "_email_new_value", None)
        is_active_new_value = getattr(self, "_is_active_new_value", None)
        full_name_new_value = getattr(self, "_full_name_new_value", None)
        password = getattr(self, "_password_set_to", None)

        # Clean up the internal "pending change" state, now that we've
        # fetched the values:
        self._email_new_value = None
        self._is_active_new_value = None
        self._full_name_new_value = None
        self._password_set_to = None

        if email_new_value:
            try:
                # Note that the validate_email check that usually
                # appears adjacent to email_allowed_for_realm is
                # present in save().
                email_allowed_for_realm(email_new_value, realm)
            except DomainNotAllowedForRealmError:
                raise scim_exceptions.BadRequestError(
                    "This email domain isn't allowed in this organization.")
            except DisposableEmailError:  # nocoverage
                raise scim_exceptions.BadRequestError(
                    "Disposable email domains are not allowed for this realm.")
            except EmailContainsPlusError:  # nocoverage
                raise scim_exceptions.BadRequestError(
                    "Email address can't contain + characters.")

            try:
                validate_email_not_already_in_realm(realm, email_new_value)
            except ValidationError as e:
                raise ConflictError("Email address already in use: " + str(e))

        if self.is_new_user():
            assert full_name_new_value is not None
            self.obj = do_create_user(
                email_new_value,
                password,
                realm,
                full_name_new_value,
                acting_user=None,
            )
            return

        # TODO: The below operations should ideally be executed in a single
        # atomic block to avoid failing with partial changes getting saved.
        # This can be fixed once we figure out how do_deactivate_user can be run
        # inside an atomic block.

        # We process full_name first here, since it's the only one that can fail.
        if full_name_new_value:
            check_change_full_name(self.obj,
                                   full_name_new_value,
                                   acting_user=None)

        if email_new_value:
            do_change_user_delivery_email(self.obj, email_new_value)

        if is_active_new_value is not None and is_active_new_value:
            do_reactivate_user(self.obj, acting_user=None)
        elif is_active_new_value is not None and not is_active_new_value:
            do_deactivate_user(self.obj, acting_user=None)
Esempio n. 18
0
def accounts_register(
    request: HttpRequest,
    key: str = REQ(default=""),
    timezone: str = REQ(default="", converter=to_timezone_or_empty),
    from_confirmation: Optional[str] = REQ(default=None),
    form_full_name: Optional[str] = REQ("full_name", default=None),
    source_realm_id: Optional[int] = REQ(default=None,
                                         converter=to_converted_or_fallback(
                                             to_non_negative_int, None)),
) -> HttpResponse:
    try:
        prereg_user = check_prereg_key(request, key)
    except ConfirmationKeyException as e:
        return render_confirmation_key_error(request, e)

    email = prereg_user.email
    realm_creation = prereg_user.realm_creation
    password_required = prereg_user.password_required

    role = prereg_user.invited_as
    if realm_creation:
        role = UserProfile.ROLE_REALM_OWNER

    try:
        validators.validate_email(email)
    except ValidationError:
        return render(request,
                      "zerver/invalid_email.html",
                      context={"invalid_email": True})

    if realm_creation:
        # For creating a new realm, there is no existing realm or domain
        realm = None
    else:
        assert prereg_user.realm is not None
        if get_subdomain(request) != prereg_user.realm.string_id:
            return render_confirmation_key_error(
                request,
                ConfirmationKeyException(
                    ConfirmationKeyException.DOES_NOT_EXIST))
        realm = prereg_user.realm
        try:
            email_allowed_for_realm(email, realm)
        except DomainNotAllowedForRealmError:
            return render(
                request,
                "zerver/invalid_email.html",
                context={
                    "realm_name": realm.name,
                    "closed_domain": True
                },
            )
        except DisposableEmailError:
            return render(
                request,
                "zerver/invalid_email.html",
                context={
                    "realm_name": realm.name,
                    "disposable_emails_not_allowed": True
                },
            )
        except EmailContainsPlusError:
            return render(
                request,
                "zerver/invalid_email.html",
                context={
                    "realm_name": realm.name,
                    "email_contains_plus": True
                },
            )

        if realm.deactivated:
            # The user is trying to register for a deactivated realm. Advise them to
            # contact support.
            return redirect_to_deactivation_notice()

        try:
            validate_email_not_already_in_realm(realm, email)
        except ValidationError:
            return redirect_to_email_login_url(email)

        if settings.BILLING_ENABLED:
            try:
                check_spare_licenses_available_for_registering_new_user(
                    realm, email)
            except LicenseLimitError:
                return render(request, "zerver/no_spare_licenses.html")

    name_validated = False
    require_ldap_password = False

    if from_confirmation:
        try:
            del request.session["authenticated_full_name"]
        except KeyError:
            pass

        ldap_full_name = None
        if settings.POPULATE_PROFILE_VIA_LDAP:
            # If the user can be found in LDAP, we'll take the full name from the directory,
            # and further down create a form pre-filled with it.
            for backend in get_backends():
                if isinstance(backend, LDAPBackend):
                    try:
                        ldap_username = backend.django_to_ldap_username(email)
                    except ZulipLDAPExceptionNoMatchingLDAPUser:
                        logging.warning(
                            "New account email %s could not be found in LDAP",
                            email)
                        break

                    # Note that this `ldap_user` object is not a
                    # `ZulipLDAPUser` with a `Realm` attached, so
                    # calling `.populate_user()` on it will crash.
                    # This is OK, since we're just accessing this user
                    # to extract its name.
                    #
                    # TODO: We should potentially be accessing this
                    # user to sync its initial avatar and custom
                    # profile fields as well, if we indeed end up
                    # creating a user account through this flow,
                    # rather than waiting until `manage.py
                    # sync_ldap_user_data` runs to populate it.
                    ldap_user = _LDAPUser(backend, ldap_username)

                    try:
                        ldap_full_name = backend.get_mapped_name(ldap_user)
                    except TypeError:
                        break

                    # Check whether this is ZulipLDAPAuthBackend,
                    # which is responsible for authentication and
                    # requires that LDAP accounts enter their LDAP
                    # password to register, or ZulipLDAPUserPopulator,
                    # which just populates UserProfile fields (no auth).
                    require_ldap_password = isinstance(backend,
                                                       ZulipLDAPAuthBackend)
                    break

        if ldap_full_name:
            # 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},
                                    realm_creation=realm_creation)
            request.session["authenticated_full_name"] = ldap_full_name
            name_validated = True
        elif 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 ""
                },
                realm_creation=realm_creation,
            )
            name_validated = True
        elif prereg_user.full_name:
            if prereg_user.full_name_validated:
                request.session[
                    "authenticated_full_name"] = prereg_user.full_name
                name_validated = True
                form = RegistrationForm({"full_name": prereg_user.full_name},
                                        realm_creation=realm_creation)
            else:
                form = RegistrationForm(
                    initial={"full_name": prereg_user.full_name},
                    realm_creation=realm_creation)
        elif form_full_name is not None:
            form = RegistrationForm(
                initial={"full_name": form_full_name},
                realm_creation=realm_creation,
            )
        else:
            form = RegistrationForm(realm_creation=realm_creation)
    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, realm_creation=realm_creation)

    if not (password_auth_enabled(realm) and password_required):
        form["password"].field.required = False

    if form.is_valid():
        if password_auth_enabled(realm) and form["password"].field.required:
            password = form.cleaned_data["password"]
        else:
            # If the user wasn't prompted for a password when
            # completing the authentication form (because they're
            # signing up with SSO and no password is required), set
            # the password field to `None` (Which causes Django to
            # create an unusable password).
            password = None

        if realm_creation:
            string_id = form.cleaned_data["realm_subdomain"]
            realm_name = form.cleaned_data["realm_name"]
            realm_type = form.cleaned_data["realm_type"]
            is_demo_org = form.cleaned_data["is_demo_organization"]
            realm = do_create_realm(string_id,
                                    realm_name,
                                    org_type=realm_type,
                                    is_demo_organization=is_demo_org)
        assert realm is not None

        full_name = form.cleaned_data["full_name"]
        enable_marketing_emails = form.cleaned_data["enable_marketing_emails"]
        default_stream_group_names = request.POST.getlist(
            "default_stream_group")
        default_stream_groups = lookup_default_stream_groups(
            default_stream_group_names, realm)

        if source_realm_id is not None:
            # Non-integer realm_id values like "string" are treated
            # like the "Do not import" value of "".
            source_profile: Optional[UserProfile] = get_source_profile(
                email, source_realm_id)
        else:
            source_profile = None

        if not realm_creation:
            try:
                existing_user_profile: Optional[
                    UserProfile] = get_user_by_delivery_email(email, realm)
            except UserProfile.DoesNotExist:
                existing_user_profile = None
        else:
            existing_user_profile = None

        user_profile: Optional[UserProfile] = None
        return_data: Dict[str, bool] = {}
        if ldap_auth_enabled(realm):
            # If the user was authenticated using an external SSO
            # mechanism like Google or GitHub auth, then authentication
            # will have already been done before creating the
            # PreregistrationUser object with password_required=False, and
            # so we don't need to worry about passwords.
            #
            # If instead the realm is using EmailAuthBackend, we will
            # set their password above.
            #
            # But if the realm is using LDAPAuthBackend, we need to verify
            # their LDAP password (which will, as a side effect, create
            # the user account) here using authenticate.
            # prereg_user.realm_creation carries the information about whether
            # we're in realm creation mode, and the ldap flow will handle
            # that and create the user with the appropriate parameters.
            user_profile = authenticate(
                request=request,
                username=email,
                password=password,
                realm=realm,
                prereg_user=prereg_user,
                return_data=return_data,
            )
            if user_profile is None:
                can_use_different_backend = email_auth_enabled(realm) or (len(
                    get_external_method_dicts(realm)) > 0)
                if settings.LDAP_APPEND_DOMAIN:
                    # In LDAP_APPEND_DOMAIN configurations, we don't allow making a non-LDAP account
                    # if the email matches the ldap domain.
                    can_use_different_backend = can_use_different_backend and (
                        not email_belongs_to_ldap(realm, email))
                if return_data.get(
                        "no_matching_ldap_user") and can_use_different_backend:
                    # If both the LDAP and Email or Social auth backends are
                    # enabled, and there's no matching user in the LDAP
                    # directory then the intent is to create a user in the
                    # realm with their email outside the LDAP organization
                    # (with e.g. a password stored in the Zulip database,
                    # not LDAP).  So we fall through and create the new
                    # account.
                    pass
                else:
                    # TODO: This probably isn't going to give a
                    # user-friendly error message, but it doesn't
                    # particularly matter, because the registration form
                    # is hidden for most users.
                    view_url = reverse("login")
                    query = urlencode({"email": email})
                    redirect_url = append_url_query_string(view_url, query)
                    return HttpResponseRedirect(redirect_url)
            elif not realm_creation:
                # Since we'll have created a user, we now just log them in.
                return login_and_go_to_home(request, user_profile)
            else:
                # With realm_creation=True, we're going to return further down,
                # after finishing up the creation process.
                pass

        if existing_user_profile is not None and existing_user_profile.is_mirror_dummy:
            user_profile = existing_user_profile
            do_activate_mirror_dummy_user(user_profile,
                                          acting_user=user_profile)
            do_change_password(user_profile, password)
            do_change_full_name(user_profile, full_name, user_profile)
            do_change_user_setting(user_profile,
                                   "timezone",
                                   timezone,
                                   acting_user=user_profile)
            do_change_user_setting(
                user_profile,
                "default_language",
                get_default_language_for_new_user(request, realm),
                acting_user=None,
            )
            # TODO: When we clean up the `do_activate_mirror_dummy_user` code path,
            # make it respect invited_as_admin / is_realm_admin.

        if user_profile is None:
            user_profile = do_create_user(
                email,
                password,
                realm,
                full_name,
                prereg_user=prereg_user,
                role=role,
                tos_version=settings.TERMS_OF_SERVICE_VERSION,
                timezone=timezone,
                default_language=get_default_language_for_new_user(
                    request, realm),
                default_stream_groups=default_stream_groups,
                source_profile=source_profile,
                realm_creation=realm_creation,
                acting_user=None,
                enable_marketing_emails=enable_marketing_emails,
            )

        if realm_creation:
            # 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(
                ExternalAuthResult(user_profile=user_profile,
                                   data_dict={"is_realm_creation": True}))

        # This dummy_backend check below confirms the user is
        # authenticating to the correct subdomain.
        auth_result = authenticate(
            username=user_profile.delivery_email,
            realm=realm,
            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.delivery_email,
            )
            return redirect("/")

        return login_and_go_to_home(request, auth_result)

    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,
            "password_required":
            password_auth_enabled(realm) and password_required,
            "require_ldap_password":
            require_ldap_password,
            "password_auth_enabled":
            password_auth_enabled(realm),
            "root_domain_available":
            is_root_domain_available(),
            "default_stream_groups":
            [] if realm is None else get_default_stream_groups(realm),
            "accounts":
            get_accounts_for_email(email),
            "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),
            "corporate_enabled":
            settings.CORPORATE_ENABLED,
            "sorted_realm_types":
            sorted(Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]),
        },
    )
Esempio n. 19
0
 def setUp(self) -> None:
     super().setUp()
     self.user = do_create_user(
         "*****@*****.**", "password", get_realm("zulip"), "user", acting_user=None
     )
Esempio n. 20
0
    def add_message_formatting_conversation(self) -> None:
        realm = get_realm("zulip")
        stream = ensure_stream(realm, "zulip features", acting_user=None)

        UserProfile.objects.filter(email__contains="stage").delete()
        starr = do_create_user("*****@*****.**",
                               "password",
                               realm,
                               "Ada Starr",
                               acting_user=None)
        self.set_avatar(starr, "static/images/characters/starr.png")
        fisher = do_create_user("*****@*****.**",
                                "password",
                                realm,
                                "Bel Fisher",
                                acting_user=None)
        self.set_avatar(fisher, "static/images/characters/fisher.png")
        twitter_bot = do_create_user(
            "*****@*****.**",
            "password",
            realm,
            "Twitter Bot",
            bot_type=UserProfile.DEFAULT_BOT,
            acting_user=None,
        )
        self.set_avatar(twitter_bot, "static/images/features/twitter.png")

        bulk_add_subscriptions(realm, [stream],
                               list(UserProfile.objects.filter(realm=realm)),
                               acting_user=None)

        staged_messages: List[Dict[str, Any]] = [
            {
                "sender":
                starr,
                "content":
                "Hey @**Bel Fisher**, check out Zulip's Markdown formatting! "
                "You can have:\n* bulleted lists\n  * with sub-bullets too\n"
                "* **bold**, *italic*, and ~~strikethrough~~ text\n"
                "* LaTeX for mathematical formulas, both inline -- $$O(n^2)$$ -- and displayed:\n"
                "```math\n\\int_a^b f(t)\\, dt=F(b)-F(a)\n```",
            },
            {
                "sender":
                fisher,
                "content":
                "My favorite is the syntax highlighting for code blocks\n"
                "```python\ndef fib(n: int) -> int:\n    # returns the n-th Fibonacci number\n"
                "    return fib(n-1) + fib(n-2)\n```",
            },
            {
                "sender":
                starr,
                "content":
                "I think you forgot your base case there, Bel :laughing:\n"
                "```quote\n```python\ndef fib(n: int) -> int:\n    # returns the n-th Fibonacci number\n"
                "    return fib(n-1) + fib(n-2)\n```\n```",
            },
            {
                "sender":
                fisher,
                "content":
                "I'm also a big fan of inline link, tweet, video, and image previews. "
                "Check out this picture of Çet Whalin[](/static/images/features/whale.png)!",
            },
            {
                "sender":
                starr,
                "content":
                "I just set up a custom linkifier, "
                "so `#1234` becomes [#1234](github.com/zulip/zulip/1234), "
                "a link to the corresponding GitHub issue.",
            },
            {
                "sender":
                twitter_bot,
                "content":
                "https://twitter.com/gvanrossum/status/786661035637772288",
            },
            {
                "sender":
                fisher,
                "content":
                "Oops, the Twitter bot I set up shouldn't be posting here. Let me go fix that.",
            },
        ]

        messages = [
            internal_prep_stream_message(
                message["sender"],
                stream,
                "message formatting",
                message["content"],
            ) for message in staged_messages
        ]

        message_ids = do_send_messages(messages)

        preview_message = Message.objects.get(
            id__in=message_ids, content__icontains="image previews")
        (emoji_code, reaction_type) = emoji_name_to_emoji_code(realm, "whale")
        do_add_reaction(starr, preview_message, "whale", emoji_code,
                        reaction_type)

        twitter_message = Message.objects.get(id__in=message_ids,
                                              content__icontains="gvanrossum")
        # Setting up a twitter integration in dev is a decent amount of work. If you need
        # to update this tweet, either copy the format below, or send the link to the tweet
        # to chat.zulip.org and ask an admin of that server to get you the rendered_content.
        twitter_message.rendered_content = (
            "<p><a>https://twitter.com/gvanrossum/status/786661035637772288</a></p>\n"
            '<div class="inline-preview-twitter"><div class="twitter-tweet">'
            '<a><img class="twitter-avatar" '
            'src="https://pbs.twimg.com/profile_images/424495004/GuidoAvatar_bigger.jpg"></a>'
            "<p>Great blog post about Zulip's use of mypy: "
            "<a>http://blog.zulip.org/2016/10/13/static-types-in-python-oh-mypy/</a></p>"
            "<span>- Guido van Rossum (@gvanrossum)</span></div></div>")
        twitter_message.save(update_fields=["rendered_content"])

        # Put a short pause between the whale reaction and this, so that the
        # thumbs_up shows up second
        (emoji_code,
         reaction_type) = emoji_name_to_emoji_code(realm, "thumbs_up")
        do_add_reaction(starr, preview_message, "thumbs_up", emoji_code,
                        reaction_type)
Esempio n. 21
0
def add_bot_backend(
    request: HttpRequest,
    user_profile: UserProfile,
    full_name_raw: str = REQ("full_name"),
    short_name_raw: str = REQ("short_name"),
    bot_type: int = REQ(json_validator=check_int,
                        default=UserProfile.DEFAULT_BOT),
    payload_url: str = REQ(json_validator=check_url, default=""),
    service_name: Optional[str] = REQ(default=None),
    config_data: Dict[str, str] = REQ(
        default={}, json_validator=check_dict(value_validator=check_string)),
    interface_type: int = REQ(json_validator=check_int,
                              default=Service.GENERIC),
    default_sending_stream_name: Optional[str] = REQ("default_sending_stream",
                                                     default=None),
    default_events_register_stream_name: Optional[str] = REQ(
        "default_events_register_stream", default=None),
    default_all_public_streams: Optional[bool] = REQ(json_validator=check_bool,
                                                     default=None),
) -> HttpResponse:
    short_name = check_short_name(short_name_raw)
    if bot_type != UserProfile.INCOMING_WEBHOOK_BOT:
        service_name = service_name or short_name
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    try:
        email = f"{short_name}@{user_profile.realm.get_bot_domain()}"
    except InvalidFakeEmailDomain:
        raise JsonableError(
            _("Can't create bots until FAKE_EMAIL_DOMAIN is correctly configured.\n"
              "Please contact your server administrator."))
    form = CreateUserForm({"full_name": full_name, "email": email})

    if bot_type == UserProfile.EMBEDDED_BOT:
        if not settings.EMBEDDED_BOTS_ENABLED:
            raise JsonableError(_("Embedded bots are not enabled."))
        if service_name not in [bot.name for bot in EMBEDDED_BOTS]:
            raise JsonableError(_("Invalid embedded bot name."))

    if not form.is_valid():
        # We validate client-side as well
        raise JsonableError(_("Bad name or username"))
    try:
        get_user_by_delivery_email(email, user_profile.realm)
        raise JsonableError(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass

    check_bot_name_available(
        realm_id=user_profile.realm_id,
        full_name=full_name,
    )

    check_bot_creation_policy(user_profile, bot_type)
    check_valid_bot_type(user_profile, bot_type)
    check_valid_interface_type(interface_type)

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        raise JsonableError(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream,
         ignored_sub) = access_stream_by_name(user_profile,
                                              default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_sub) = access_stream_by_name(
            user_profile, default_events_register_stream_name)

    if bot_type in (UserProfile.INCOMING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT) and service_name:
        check_valid_bot_config(bot_type, service_name, config_data)

    bot_profile = do_create_user(
        email=email,
        password=None,
        realm=user_profile.realm,
        full_name=full_name,
        bot_type=bot_type,
        bot_owner=user_profile,
        avatar_source=avatar_source,
        default_sending_stream=default_sending_stream,
        default_events_register_stream=default_events_register_stream,
        default_all_public_streams=default_all_public_streams,
        acting_user=user_profile,
    )
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        assert isinstance(user_file, UploadedFile)
        assert user_file.size is not None
        upload_avatar_image(user_file, user_profile, bot_profile)

    if bot_type in (UserProfile.OUTGOING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT):
        assert isinstance(service_name, str)
        add_service(
            name=service_name,
            user_profile=bot_profile,
            base_url=payload_url,
            interface=interface_type,
            token=generate_api_key(),
        )

    if bot_type == UserProfile.INCOMING_WEBHOOK_BOT and service_name:
        set_bot_config(bot_profile, "integration_id", service_name)

    if bot_type in (UserProfile.INCOMING_WEBHOOK_BOT,
                    UserProfile.EMBEDDED_BOT):
        for key, value in config_data.items():
            set_bot_config(bot_profile, key, value)

    notify_created_bot(bot_profile)

    api_key = get_api_key(bot_profile)

    json_result = dict(
        user_id=bot_profile.id,
        api_key=api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(
            bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(
            bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(request, data=json_result)