Skip to content

Commit 582bfe8

Browse files
authored
fix: update domain status during verification (#18357)
1 parent 5a3e4b3 commit 582bfe8

File tree

4 files changed

+101
-101
lines changed

4 files changed

+101
-101
lines changed

tests/conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from warehouse.organizations.interfaces import IOrganizationService
5959
from warehouse.packaging import services as packaging_services
6060
from warehouse.packaging.interfaces import IProjectService
61+
from warehouse.rate_limiting import DummyRateLimiter, IRateLimiter
6162
from warehouse.search import services as search_services
6263
from warehouse.search.interfaces import ISearchService
6364
from warehouse.subscriptions import services as subscription_services
@@ -164,6 +165,7 @@ def pyramid_services(
164165
query_results_cache_service,
165166
search_service,
166167
domain_status_service,
168+
ratelimit_service,
167169
):
168170
services = _Services()
169171

@@ -190,6 +192,8 @@ def pyramid_services(
190192
services.register_service(query_results_cache_service, IQueryResultsCache)
191193
services.register_service(search_service, ISearchService)
192194
services.register_service(domain_status_service, IDomainStatusService)
195+
services.register_service(ratelimit_service, IRateLimiter, name="email.add")
196+
services.register_service(ratelimit_service, IRateLimiter, name="email.verify")
193197

194198
return services
195199

@@ -550,6 +554,13 @@ def domain_status_service(mocker):
550554
return service
551555

552556

557+
@pytest.fixture
558+
def ratelimit_service(mocker):
559+
service = DummyRateLimiter()
560+
mocker.spy(service, "clear")
561+
return service
562+
563+
553564
class QueryRecorder:
554565
def __init__(self):
555566
self.queries = []

tests/unit/accounts/test_views.py

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
from warehouse.accounts import views
2626
from warehouse.accounts.interfaces import (
27+
IDomainStatusService,
2728
IPasswordBreachedService,
2829
ITokenService,
2930
IUserService,
@@ -2575,52 +2576,47 @@ class TestVerifyEmail:
25752576
],
25762577
)
25772578
def test_verify_email(
2578-
self, db_request, user_service, token_service, is_primary, confirm_message
2579+
self, mocker, db_request, ratelimit_service, is_primary, confirm_message
25792580
):
25802581
user = UserFactory(is_active=False, totp_secret=None)
25812582
email = EmailFactory(user=user, verified=False, primary=is_primary)
25822583
db_request.user = user
25832584
db_request.GET.update({"token": "RANDOM_KEY"})
2584-
db_request.route_path = pretend.call_recorder(lambda name: "/")
2585-
token_service.loads = pretend.call_recorder(
2586-
lambda token: {"action": "email-verify", "email.id": str(email.id)}
2587-
)
2588-
email_limiter = pretend.stub(clear=pretend.call_recorder(lambda a: None))
2589-
verify_limiter = pretend.stub(clear=pretend.call_recorder(lambda a: None))
2590-
services = {
2591-
"email": token_service,
2592-
"email.add": email_limiter,
2593-
"email.verify": verify_limiter,
2594-
}
2595-
db_request.find_service = pretend.call_recorder(
2596-
lambda a, name, **kwargs: services[name]
2585+
db_request.route_path = mocker.Mock(return_value="/")
2586+
mock_token_service_loads = mocker.patch(
2587+
"warehouse.accounts.services.TokenService.loads",
2588+
return_value={"action": "email-verify", "email.id": str(email.id)},
25972589
)
2598-
db_request.session.flash = pretend.call_recorder(lambda *a, **kw: None)
2590+
spy_find_service = mocker.spy(db_request, "find_service")
2591+
spy_session_flash = mocker.spy(db_request.session, "flash")
25992592

26002593
result = views.verify_email(db_request)
26012594

26022595
db_request.db.flush()
26032596
assert email.verified
2597+
assert email.domain_last_status == ["active"]
26042598
assert user.is_active
26052599
assert isinstance(result, HTTPSeeOther)
26062600
assert result.headers["Location"] == "/"
2607-
assert db_request.route_path.calls == [
2608-
pretend.call("manage.account.two-factor")
2609-
]
2610-
assert token_service.loads.calls == [pretend.call("RANDOM_KEY")]
2611-
assert email_limiter.clear.calls == [pretend.call(db_request.remote_addr)]
2612-
assert verify_limiter.clear.calls == [pretend.call(user.id)]
2613-
assert db_request.session.flash.calls == [
2614-
pretend.call(
2615-
f"Email address {email.email} verified. " + confirm_message,
2616-
queue="success",
2617-
)
2618-
]
2619-
assert db_request.find_service.calls == [
2620-
pretend.call(ITokenService, name="email"),
2621-
pretend.call(IRateLimiter, name="email.add"),
2622-
pretend.call(IRateLimiter, name="email.verify"),
2623-
]
2601+
db_request.route_path.assert_called_once_with("manage.account.two-factor")
2602+
mock_token_service_loads.assert_called_once_with("RANDOM_KEY")
2603+
ratelimit_service.clear.assert_has_calls(
2604+
[
2605+
mocker.call(db_request.remote_addr),
2606+
mocker.call(user.id),
2607+
]
2608+
)
2609+
spy_session_flash.assert_called_once_with(
2610+
f"Email address {email.email} verified. " + confirm_message, queue="success"
2611+
)
2612+
spy_find_service.assert_has_calls(
2613+
[
2614+
mocker.call(ITokenService, name="email"),
2615+
mocker.call(IRateLimiter, name="email.add"),
2616+
mocker.call(IRateLimiter, name="email.verify"),
2617+
mocker.call(IDomainStatusService),
2618+
]
2619+
)
26242620

26252621
@pytest.mark.parametrize(
26262622
("exception", "message"),
@@ -2702,34 +2698,24 @@ def test_verify_email_already_verified(self, db_request):
27022698
pretend.call("Email already verified", queue="error")
27032699
]
27042700

2705-
def test_verify_email_with_existing_2fa(self, db_request, token_service):
2701+
def test_verify_email_with_existing_2fa(self, mocker, db_request):
27062702
user = UserFactory(is_active=False, totp_secret=b"secret")
27072703
email = EmailFactory(user=user, verified=False, primary=False)
27082704
db_request.user = user
27092705
db_request.GET.update({"token": "RANDOM_KEY"})
2710-
db_request.route_path = pretend.call_recorder(lambda name: "/")
2711-
token_service.loads = pretend.call_recorder(
2712-
lambda token: {"action": "email-verify", "email.id": str(email.id)}
2713-
)
2714-
email_limiter = pretend.stub(clear=pretend.call_recorder(lambda a: None))
2715-
verify_limiter = pretend.stub(clear=pretend.call_recorder(lambda a: None))
2716-
services = {
2717-
"email": token_service,
2718-
"email.add": email_limiter,
2719-
"email.verify": verify_limiter,
2720-
}
2721-
db_request.find_service = pretend.call_recorder(
2722-
lambda a, name, **kwargs: services[name]
2706+
db_request.route_path = mocker.Mock(return_value="/")
2707+
mocker.patch(
2708+
"warehouse.accounts.services.TokenService.loads",
2709+
return_value={"action": "email-verify", "email.id": str(email.id)},
27232710
)
2724-
db_request.session.flash = pretend.call_recorder(lambda *a, **kw: None)
27252711

27262712
assert db_request.user.has_two_factor
27272713

27282714
result = views.verify_email(db_request)
27292715

27302716
assert isinstance(result, HTTPSeeOther)
27312717
assert result.headers["Location"] == "/"
2732-
assert db_request.route_path.calls == [pretend.call("manage.account")]
2718+
db_request.route_path.assert_called_once_with("manage.account")
27332719
assert db_request.user.is_active
27342720

27352721

warehouse/accounts/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
TooManyPasswordResetRequests,
5151
)
5252
from warehouse.accounts.models import Email, TermsOfServiceEngagement, User
53+
from warehouse.accounts.utils import update_email_domain_status
5354
from warehouse.admin.flags import AdminFlagValue
5455
from warehouse.authnz import Permissions
5556
from warehouse.cache.origin import origin_cache
@@ -1006,6 +1007,8 @@ def _error(message):
10061007

10071008
if email.verified:
10081009
return _error(request._("Email already verified"))
1010+
# Run the domain status update now that the end user has verified it.
1011+
update_email_domain_status(email, request)
10091012

10101013
email.verified = True
10111014
email.unverify_reason = None

0 commit comments

Comments
 (0)