Skip to content

Commit c84da1e

Browse files
committed
Get # of days from config
- Also cleaned up tests - Also changed cookie to strict
1 parent 25af6b8 commit c84da1e

File tree

5 files changed

+50
-21
lines changed

5 files changed

+50
-21
lines changed

tests/unit/accounts/test_views.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import json
1515
import uuid
1616

17+
from datetime import timedelta
18+
1719
import freezegun
1820
import pretend
1921
import pytest
@@ -48,7 +50,6 @@
4850
)
4951
from warehouse.accounts.views import (
5052
REMEMBER_DEVICE_COOKIE,
51-
REMEMBER_DEVICE_SECONDS,
5253
two_factor_and_totp_validate,
5354
)
5455
from warehouse.admin.flags import AdminFlag, AdminFlagValue
@@ -600,7 +601,7 @@ def test_get_returns_totp_form(self, pyramid_request, redirect_url):
600601
ITokenService: token_service,
601602
IUserService: user_service,
602603
}[interface]
603-
604+
pyramid_request.registry.settings = {"remember_device.days": 30}
604605
pyramid_request.query_string = pretend.stub()
605606

606607
form_obj = pretend.stub()
@@ -613,7 +614,7 @@ def test_get_returns_totp_form(self, pyramid_request, redirect_url):
613614
assert token_service.loads.calls == [
614615
pretend.call(pyramid_request.query_string, return_timestamp=True)
615616
]
616-
assert result == {"totp_form": form_obj}
617+
assert result == {"totp_form": form_obj, "remember_device_days": 30}
617618
assert form_class.calls == [
618619
pretend.call(
619620
pyramid_request.POST,
@@ -653,16 +654,17 @@ def test_get_returns_webauthn(self, pyramid_request, redirect_url):
653654
ITokenService: token_service,
654655
IUserService: user_service,
655656
}[interface]
656-
657+
pyramid_request.registry.settings = {"remember_device.days": 30}
657658
pyramid_request.query_string = pretend.stub()
659+
658660
result = views.two_factor_and_totp_validate(
659661
pyramid_request, _form_class=pretend.stub()
660662
)
661663

662664
assert token_service.loads.calls == [
663665
pretend.call(pyramid_request.query_string, return_timestamp=True)
664666
]
665-
assert result == {"has_webauthn": True}
667+
assert result == {"has_webauthn": True, "remember_device_days": 30}
666668

667669
@pytest.mark.parametrize("redirect_url", [None, "/foo/bar/", "/wat/"])
668670
def test_get_returns_recovery_code_status(self, pyramid_request, redirect_url):
@@ -693,7 +695,7 @@ def test_get_returns_recovery_code_status(self, pyramid_request, redirect_url):
693695
ITokenService: token_service,
694696
IUserService: user_service,
695697
}[interface]
696-
698+
pyramid_request.registry.settings = {"remember_device.days": 30}
697699
pyramid_request.query_string = pretend.stub()
698700
result = views.two_factor_and_totp_validate(
699701
pyramid_request, _form_class=pretend.stub()
@@ -702,7 +704,7 @@ def test_get_returns_recovery_code_status(self, pyramid_request, redirect_url):
702704
assert token_service.loads.calls == [
703705
pretend.call(pyramid_request.query_string, return_timestamp=True)
704706
]
705-
assert result == {"has_recovery_codes": True}
707+
assert result == {"has_recovery_codes": True, "remember_device_days": 30}
706708

707709
@pytest.mark.parametrize("redirect_url", ["test_redirect_url", None])
708710
@pytest.mark.parametrize("has_recovery_codes", [True, False])
@@ -770,6 +772,7 @@ def test_totp_auth(
770772
lambda *args: None
771773
)
772774
pyramid_request.session.record_password_timestamp = lambda timestamp: None
775+
pyramid_request.registry.settings = {"remember_device.days": 30}
773776

774777
form_obj = pretend.stub(
775778
validate=pretend.call_recorder(lambda: True),
@@ -862,6 +865,7 @@ def test_totp_form_invalid(self):
862865
IUserService: user_service,
863866
}[interface],
864867
query_string=pretend.stub(),
868+
registry=pretend.stub(settings={"remember_device.days": 30}),
865869
)
866870

867871
form_obj = pretend.stub(
@@ -875,7 +879,7 @@ def test_totp_form_invalid(self):
875879
assert token_service.loads.calls == [
876880
pretend.call(request.query_string, return_timestamp=True)
877881
]
878-
assert result == {"totp_form": form_obj}
882+
assert result == {"totp_form": form_obj, "remember_device_days": 30}
879883

880884
def test_two_factor_token_missing_userid(self, pyramid_request):
881885
token_service = pretend.stub(
@@ -1149,7 +1153,7 @@ def test_check_remember_device_token_invalid_wrong_user(self):
11491153
)
11501154
assert not views._check_remember_device_token(request, 1)
11511155

1152-
def test_remember_device(self, monkeypatch, pyramid_request):
1156+
def test_remember_device(self):
11531157
token_service = pretend.stub(dumps=lambda *a: "token_data")
11541158
pyramid_request = pretend.stub(
11551159
find_service=lambda interface, **kwargs: {
@@ -1160,6 +1164,9 @@ def test_remember_device(self, monkeypatch, pyramid_request):
11601164
user=pretend.stub(
11611165
record_event=pretend.call_recorder(lambda *a, **kw: None)
11621166
),
1167+
registry=pretend.stub(
1168+
settings={"remember_device.seconds": timedelta(days=30).total_seconds()}
1169+
),
11631170
)
11641171
response = pretend.stub(set_cookie=pretend.call_recorder(lambda *a, **kw: None))
11651172

@@ -1169,10 +1176,10 @@ def test_remember_device(self, monkeypatch, pyramid_request):
11691176
pretend.call(
11701177
REMEMBER_DEVICE_COOKIE,
11711178
"token_data",
1172-
max_age=REMEMBER_DEVICE_SECONDS,
1179+
max_age=timedelta(days=30).total_seconds(),
11731180
httponly=True,
11741181
secure=True,
1175-
samesite=b"lax",
1182+
samesite=b"strict",
11761183
path="/accounts/login",
11771184
)
11781185
]
@@ -1236,7 +1243,6 @@ def test_get_returns_form(self, pyramid_request):
12361243
ITokenService: token_service,
12371244
IUserService: user_service,
12381245
}[interface]
1239-
12401246
pyramid_request.query_string = pretend.stub()
12411247

12421248
form_obj = pretend.stub()
@@ -1383,6 +1389,7 @@ def test_recovery_code_form_invalid(self):
13831389
IUserService: user_service,
13841390
}[interface],
13851391
query_string=pretend.stub(),
1392+
# registry=pretend.stub(settings={"remember_device.days": 30}),
13861393
)
13871394

13881395
form_obj = pretend.stub(

tests/unit/test_config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import os
1414

15+
from datetime import timedelta
1516
from unittest import mock
1617

1718
import orjson
@@ -246,7 +247,9 @@ def __init__(self):
246247
"warehouse.commit": "null",
247248
"site.name": "Warehouse",
248249
"token.two_factor.max_age": 300,
249-
"token.remember_device.max_age": 2592000,
250+
"remember_device.days": 30,
251+
"remember_device.seconds": timedelta(days=30).total_seconds(),
252+
"token.remember_device.max_age": timedelta(days=30).total_seconds(),
250253
"token.default.max_age": 21600,
251254
"pythondotorg.host": "https://www.python.org",
252255
"warehouse.xmlrpc.client.ratelimit_string": "3600 per hour",

warehouse/accounts/views.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494

9595
USER_ID_INSECURE_COOKIE = "user_id__insecure"
9696
REMEMBER_DEVICE_COOKIE = "remember_device"
97-
REMEMBER_DEVICE_SECONDS = 2592000 # 30 days
9897

9998

10099
@view_config(context=TooManyFailedLogins, has_translations=True)
@@ -334,6 +333,9 @@ def two_factor_and_totp_validate(request, _form_class=TOTPAuthenticationForm):
334333
two_factor_state["has_webauthn"] = True
335334
if user_service.has_recovery_codes(userid):
336335
two_factor_state["has_recovery_codes"] = True
336+
two_factor_state["remember_device_days"] = request.registry.settings[
337+
"remember_device.days"
338+
]
337339

338340
if request.method == "POST":
339341
form = two_factor_state["totp_form"]
@@ -484,10 +486,10 @@ def _remember_device(request, response, userid, two_factor_method) -> None:
484486
response.set_cookie(
485487
REMEMBER_DEVICE_COOKIE,
486488
token,
487-
max_age=REMEMBER_DEVICE_SECONDS,
489+
max_age=request.registry.settings["remember_device.seconds"],
488490
httponly=True,
489491
secure=request.scheme == "https",
490-
samesite=b"lax",
492+
samesite=b"strict",
491493
path=request.route_path("accounts.login"),
492494
)
493495
request.user.record_event(

warehouse/config.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import os
1818
import shlex
1919

20+
from datetime import timedelta
21+
2022
import orjson
2123
import transaction
2224

@@ -241,10 +243,17 @@ def configure(settings=None):
241243
)
242244
maybe_set(
243245
settings,
244-
"token.remember_device.max_age",
245-
"TOKEN_REMEMBER_DEVICE_MAX_AGE",
246+
"remember_device.days",
247+
"REMEMBER_DEVICE_DAYS",
246248
coercer=int,
247-
default=2592000, # 30 days,
249+
default=30,
250+
)
251+
settings.setdefault(
252+
"remember_device.seconds",
253+
timedelta(days=settings.get("remember_device.days")).total_seconds(),
254+
)
255+
settings.setdefault(
256+
"token.remember_device.max_age", settings.get("remember_device.seconds")
248257
)
249258
maybe_set(
250259
settings,

warehouse/templates/accounts/two-factor.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ <h2>
6161
<div class="form-group">
6262
<label>
6363
<input type="checkbox" id="remember_device_webauthn" name="remember_device" value="true" />
64-
{% trans %}Remember this device for 30 days{% endtrans %}
64+
{% trans remember_device_days=remember_device_days %}
65+
Remember this device for {{ remember_device_days }} day
66+
{% pluralize %}
67+
Remember this device for {{ remember_device_days }} days
68+
{% endtrans %}
6569
</label>
6670
</div>
6771

@@ -123,7 +127,11 @@ <h2>{% trans %}Authenticate with an app{% endtrans %}</h2>
123127
<div class="form-group">
124128
<label>
125129
<input type="checkbox" name="remember_device" value="true" />
126-
{% trans %}Remember this device for 30 days{% endtrans %}
130+
{% trans remember_device_days=remember_device_days %}
131+
Remember this device for {{ remember_device_days }} day
132+
{% pluralize %}
133+
Remember this device for {{ remember_device_days }} days
134+
{% endtrans %}
127135
</label>
128136
</div>
129137

0 commit comments

Comments
 (0)