2017-01-20 12:27:38 +01:00
|
|
|
import datetime
|
|
|
|
|
|
|
|
from django.core import mail
|
|
|
|
from django.utils.timezone import now
|
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
from confirmation.models import Confirmation, confirmation_url, generate_key
|
|
|
|
from zerver.lib.actions import do_set_realm_property, do_start_email_change_process
|
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
|
|
from zerver.models import (
|
|
|
|
EmailChangeStatus,
|
|
|
|
Realm,
|
|
|
|
UserProfile,
|
|
|
|
get_realm,
|
|
|
|
get_user,
|
|
|
|
get_user_by_delivery_email,
|
|
|
|
get_user_profile_by_id,
|
2017-01-20 12:27:38 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class EmailChangeTestCase(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_confirm_email_change_with_non_existent_key(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-01-20 12:27:38 +01:00
|
|
|
key = generate_key()
|
2020-06-14 01:36:12 +02:00
|
|
|
url = confirmation_url(key, None, Confirmation.EMAIL_CHANGE)
|
2017-01-20 12:27:38 +01:00
|
|
|
response = self.client_get(url)
|
2017-07-22 00:27:45 +02:00
|
|
|
self.assert_in_success_response(["Whoops. We couldn't find your confirmation link in the system."], response)
|
2017-01-20 12:27:38 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_confirm_email_change_with_invalid_key(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2019-08-27 05:45:37 +02:00
|
|
|
key = 'invalid_key'
|
2020-06-14 01:36:12 +02:00
|
|
|
url = confirmation_url(key, None, Confirmation.EMAIL_CHANGE)
|
2017-01-20 12:27:38 +01:00
|
|
|
response = self.client_get(url)
|
2017-07-22 00:27:45 +02:00
|
|
|
self.assert_in_success_response(["Whoops. The confirmation link is malformed."], response)
|
2017-01-20 12:27:38 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_confirm_email_change_when_time_exceeded(self) -> None:
|
2017-05-07 21:25:59 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
|
|
|
old_email = user_profile.email
|
2017-01-20 12:27:38 +01:00
|
|
|
new_email = 'hamlet-new@zulip.com'
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-01-20 12:27:38 +01:00
|
|
|
obj = EmailChangeStatus.objects.create(new_email=new_email,
|
|
|
|
old_email=old_email,
|
|
|
|
user_profile=user_profile,
|
|
|
|
realm=user_profile.realm)
|
|
|
|
key = generate_key()
|
|
|
|
date_sent = now() - datetime.timedelta(days=2)
|
2017-07-08 04:38:13 +02:00
|
|
|
Confirmation.objects.create(content_object=obj,
|
|
|
|
date_sent=date_sent,
|
2017-07-08 06:25:05 +02:00
|
|
|
confirmation_key=key,
|
|
|
|
type=Confirmation.EMAIL_CHANGE)
|
2020-06-14 01:36:12 +02:00
|
|
|
url = confirmation_url(key, user_profile.realm, Confirmation.EMAIL_CHANGE)
|
2017-01-20 12:27:38 +01:00
|
|
|
response = self.client_get(url)
|
2017-11-08 23:02:50 +01:00
|
|
|
self.assert_in_success_response(["The confirmation link has expired or been deactivated."], response)
|
2017-01-20 12:27:38 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_confirm_email_change(self) -> None:
|
2017-05-07 21:25:59 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2020-03-12 13:51:54 +01:00
|
|
|
do_set_realm_property(
|
|
|
|
user_profile.realm,
|
|
|
|
'email_address_visibility',
|
|
|
|
Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
|
|
|
|
)
|
|
|
|
|
|
|
|
old_email = user_profile.delivery_email
|
2017-01-20 12:27:38 +01:00
|
|
|
new_email = 'hamlet-new@zulip.com'
|
2017-05-23 20:57:59 +02:00
|
|
|
new_realm = get_realm('zulip')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-01-20 12:27:38 +01:00
|
|
|
obj = EmailChangeStatus.objects.create(new_email=new_email,
|
|
|
|
old_email=old_email,
|
|
|
|
user_profile=user_profile,
|
|
|
|
realm=user_profile.realm)
|
|
|
|
key = generate_key()
|
2017-07-08 04:38:13 +02:00
|
|
|
Confirmation.objects.create(content_object=obj,
|
|
|
|
date_sent=now(),
|
2017-07-08 06:25:05 +02:00
|
|
|
confirmation_key=key,
|
|
|
|
type=Confirmation.EMAIL_CHANGE)
|
2020-06-14 01:36:12 +02:00
|
|
|
url = confirmation_url(key, user_profile.realm, Confirmation.EMAIL_CHANGE)
|
2017-01-20 12:27:38 +01:00
|
|
|
response = self.client_get(url)
|
2017-03-04 06:39:45 +01:00
|
|
|
|
2017-01-20 12:27:38 +01:00
|
|
|
self.assertEqual(response.status_code, 200)
|
2017-03-18 22:48:44 +01:00
|
|
|
self.assert_in_success_response(["This confirms that the email address for your Zulip"],
|
2017-03-05 02:18:42 +01:00
|
|
|
response)
|
2018-08-02 08:47:13 +02:00
|
|
|
user_profile = get_user_by_delivery_email(new_email, new_realm)
|
2017-01-20 12:27:38 +01:00
|
|
|
self.assertTrue(bool(user_profile))
|
|
|
|
obj.refresh_from_db()
|
|
|
|
self.assertEqual(obj.status, 1)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_start_email_change_process(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2017-01-20 12:27:38 +01:00
|
|
|
do_start_email_change_process(user_profile, 'hamlet-new@zulip.com')
|
|
|
|
self.assertEqual(EmailChangeStatus.objects.count(), 1)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_end_to_end_flow(self) -> None:
|
2017-01-20 12:27:38 +01:00
|
|
|
data = {'email': 'hamlet-new@zulip.com'}
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-07-31 20:44:52 +02:00
|
|
|
url = '/json/settings'
|
2017-01-20 12:27:38 +01:00
|
|
|
self.assertEqual(len(mail.outbox), 0)
|
2017-07-31 20:44:52 +02:00
|
|
|
result = self.client_patch(url, data)
|
2017-01-20 12:27:38 +01:00
|
|
|
self.assertEqual(len(mail.outbox), 1)
|
2017-04-28 03:09:57 +02:00
|
|
|
self.assert_in_success_response(['Check your email for a confirmation link.'], result)
|
2017-01-20 12:27:38 +01:00
|
|
|
email_message = mail.outbox[0]
|
|
|
|
self.assertEqual(
|
|
|
|
email_message.subject,
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
'Verify your new email address',
|
2017-01-20 12:27:38 +01:00
|
|
|
)
|
|
|
|
body = email_message.body
|
|
|
|
self.assertIn('We received a request to change the email', body)
|
2020-06-05 23:26:35 +02:00
|
|
|
self.assertRegex(
|
|
|
|
email_message.from_email,
|
|
|
|
fr"^Zulip Account Security <{self.TOKENIZED_NOREPLY_REGEX}>\Z",
|
|
|
|
)
|
2017-01-20 12:27:38 +01:00
|
|
|
|
2020-06-14 13:32:38 +02:00
|
|
|
self.assertEqual(email_message.extra_headers["List-Id"], "Zulip Dev <zulip.testserver>")
|
|
|
|
|
2019-02-08 10:53:01 +01:00
|
|
|
activation_url = [s for s in body.split('\n') if s][2]
|
2017-01-20 12:27:38 +01:00
|
|
|
response = self.client_get(activation_url)
|
|
|
|
|
2017-03-18 22:48:44 +01:00
|
|
|
self.assert_in_success_response(["This confirms that the email address"],
|
2017-03-05 02:18:42 +01:00
|
|
|
response)
|
2017-01-20 12:27:38 +01:00
|
|
|
|
2017-08-05 19:42:59 +02:00
|
|
|
# Now confirm trying to change your email back doesn't throw an immediate error
|
|
|
|
result = self.client_patch(url, {"email": "hamlet@zulip.com"})
|
|
|
|
self.assert_in_success_response(['Check your email for a confirmation link.'], result)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_unauthorized_email_change(self) -> None:
|
2017-03-04 06:39:45 +01:00
|
|
|
data = {'email': 'hamlet-new@zulip.com'}
|
2017-05-07 19:39:30 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2017-03-21 18:08:40 +01:00
|
|
|
do_set_realm_property(user_profile.realm, 'email_changes_disabled', True)
|
2017-07-31 20:44:52 +02:00
|
|
|
url = '/json/settings'
|
|
|
|
result = self.client_patch(url, data)
|
2017-03-04 06:39:45 +01:00
|
|
|
self.assertEqual(len(mail.outbox), 0)
|
|
|
|
self.assertEqual(result.status_code, 400)
|
2017-03-05 02:18:42 +01:00
|
|
|
self.assert_in_response("Email address changes are disabled in this organization.",
|
|
|
|
result)
|
2018-02-02 16:54:26 +01:00
|
|
|
# Realm admins can change their email address even setting is disabled.
|
|
|
|
data = {'email': 'iago-new@zulip.com'}
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('iago')
|
2018-02-02 16:54:26 +01:00
|
|
|
url = '/json/settings'
|
|
|
|
result = self.client_patch(url, data)
|
|
|
|
self.assert_in_success_response(['Check your email for a confirmation link.'], result)
|
2017-03-04 06:39:45 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_email_change_already_taken(self) -> None:
|
2017-09-26 20:15:37 +02:00
|
|
|
data = {'email': 'cordelia@zulip.com'}
|
|
|
|
user_profile = self.example_user('hamlet')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2017-09-26 20:15:37 +02:00
|
|
|
|
|
|
|
url = '/json/settings'
|
|
|
|
result = self.client_patch(url, data)
|
|
|
|
self.assertEqual(len(mail.outbox), 0)
|
|
|
|
self.assertEqual(result.status_code, 400)
|
|
|
|
self.assert_in_response("Already has an account",
|
|
|
|
result)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_unauthorized_email_change_from_email_confirmation_link(self) -> None:
|
2017-03-04 06:39:45 +01:00
|
|
|
data = {'email': 'hamlet-new@zulip.com'}
|
2017-05-07 19:39:30 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2017-07-31 20:44:52 +02:00
|
|
|
url = '/json/settings'
|
2017-03-04 06:39:45 +01:00
|
|
|
self.assertEqual(len(mail.outbox), 0)
|
2017-07-31 20:44:52 +02:00
|
|
|
result = self.client_patch(url, data)
|
2017-03-04 06:39:45 +01:00
|
|
|
self.assertEqual(len(mail.outbox), 1)
|
2017-04-28 03:09:57 +02:00
|
|
|
self.assert_in_success_response(['Check your email for a confirmation link.'], result)
|
2017-03-04 06:39:45 +01:00
|
|
|
email_message = mail.outbox[0]
|
|
|
|
self.assertEqual(
|
|
|
|
email_message.subject,
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
'Verify your new email address',
|
2017-03-04 06:39:45 +01:00
|
|
|
)
|
|
|
|
body = email_message.body
|
|
|
|
self.assertIn('We received a request to change the email', body)
|
|
|
|
|
2017-03-21 18:08:40 +01:00
|
|
|
do_set_realm_property(user_profile.realm, 'email_changes_disabled', True)
|
2017-03-04 06:39:45 +01:00
|
|
|
|
2019-02-08 10:53:01 +01:00
|
|
|
activation_url = [s for s in body.split('\n') if s][2]
|
2017-03-04 06:39:45 +01:00
|
|
|
response = self.client_get(activation_url)
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 400)
|
2017-03-05 02:18:42 +01:00
|
|
|
self.assert_in_response("Email address changes are disabled in this organization.",
|
|
|
|
response)
|
2017-03-04 06:39:45 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_post_invalid_email(self) -> None:
|
2017-01-20 12:27:38 +01:00
|
|
|
data = {'email': 'hamlet-new'}
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-07-31 20:44:52 +02:00
|
|
|
url = '/json/settings'
|
|
|
|
result = self.client_patch(url, data)
|
2017-03-05 02:18:42 +01:00
|
|
|
self.assert_in_response('Invalid address', result)
|
2017-01-20 12:27:38 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_post_same_email(self) -> None:
|
2017-05-25 01:40:26 +02:00
|
|
|
data = {'email': self.example_email("hamlet")}
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-07-31 20:44:52 +02:00
|
|
|
url = '/json/settings'
|
|
|
|
result = self.client_patch(url, data)
|
2017-01-20 12:27:38 +01:00
|
|
|
self.assertEqual('success', result.json()['result'])
|
|
|
|
self.assertEqual('', result.json()['msg'])
|
2018-12-06 23:17:46 +01:00
|
|
|
|
|
|
|
def test_change_delivery_email_end_to_end_with_admins_visibility(self) -> None:
|
|
|
|
user_profile = self.example_user('hamlet')
|
|
|
|
do_set_realm_property(user_profile.realm, 'email_address_visibility',
|
|
|
|
Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS)
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2020-03-12 14:17:25 +01:00
|
|
|
old_email = user_profile.delivery_email
|
2018-12-06 23:17:46 +01:00
|
|
|
new_email = 'hamlet-new@zulip.com'
|
|
|
|
obj = EmailChangeStatus.objects.create(new_email=new_email,
|
|
|
|
old_email=old_email,
|
|
|
|
user_profile=user_profile,
|
|
|
|
realm=user_profile.realm)
|
|
|
|
key = generate_key()
|
|
|
|
Confirmation.objects.create(content_object=obj,
|
|
|
|
date_sent=now(),
|
|
|
|
confirmation_key=key,
|
|
|
|
type=Confirmation.EMAIL_CHANGE)
|
2020-06-14 01:36:12 +02:00
|
|
|
url = confirmation_url(key, user_profile.realm, Confirmation.EMAIL_CHANGE)
|
2018-12-06 23:17:46 +01:00
|
|
|
response = self.client_get(url)
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
self.assert_in_success_response(["This confirms that the email address for your Zulip"],
|
|
|
|
response)
|
|
|
|
user_profile = get_user_profile_by_id(user_profile.id)
|
|
|
|
self.assertEqual(user_profile.delivery_email, new_email)
|
2020-06-09 00:25:09 +02:00
|
|
|
self.assertEqual(user_profile.email, f"user{user_profile.id}@zulip.testserver")
|
2018-12-06 23:17:46 +01:00
|
|
|
obj.refresh_from_db()
|
|
|
|
self.assertEqual(obj.status, 1)
|
|
|
|
with self.assertRaises(UserProfile.DoesNotExist):
|
|
|
|
get_user(old_email, user_profile.realm)
|
|
|
|
with self.assertRaises(UserProfile.DoesNotExist):
|
|
|
|
get_user_by_delivery_email(old_email, user_profile.realm)
|
|
|
|
self.assertEqual(get_user_by_delivery_email(new_email, user_profile.realm), user_profile)
|