Skip to content

Commit 0ab981f

Browse files
authored
fix: enable client-side menu post-register (#18353)
1 parent eac2dcd commit 0ab981f

File tree

3 files changed

+77
-86
lines changed

3 files changed

+77
-86
lines changed

tests/unit/accounts/test_views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ def test_post_validate_redirects(
392392
assert isinstance(result, HTTPSeeOther)
393393
assert pyramid_request.route_path.calls == [pretend.call("manage.projects")]
394394
assert result.headers["Location"] == "/the-redirect"
395+
assert result.headers["Set-Cookie"].startswith("user_id__insecure=")
395396
assert result.headers["foo"] == "bar"
396397

397398
assert form_class.calls == [
@@ -1498,6 +1499,7 @@ def test_recovery_code_auth(self, monkeypatch, pyramid_request, redirect_url):
14981499
token_expected_data["redirect_to"] = redirect_url
14991500

15001501
assert isinstance(result, HTTPSeeOther)
1502+
assert result.headers["Set-Cookie"].startswith("user_id__insecure=")
15011503

15021504
assert remember.calls == [pretend.call(pyramid_request, str(1))]
15031505
assert pyramid_request.session.invalidate.calls == [pretend.call()]
@@ -1765,6 +1767,7 @@ def _find_service(service=None, name=None, context=None):
17651767

17661768
assert isinstance(result, HTTPSeeOther)
17671769
assert result.headers["Location"] == "/"
1770+
assert result.headers["Set-Cookie"].startswith("user_id__insecure=")
17681771
assert create_user.calls == [
17691772
pretend.call("username_value", "full_name", "MyStr0ng!shP455w0rd")
17701773
]

warehouse/accounts/views.py

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -344,22 +344,7 @@ def login(request, redirect_field_name=REDIRECT_FIELD_NAME, _form_class=LoginFor
344344
# either where they were trying to go originally, or to the default
345345
# view.
346346
resp = HTTPSeeOther(redirect_to, headers=dict(headers))
347-
348-
# We'll use this cookie so that client side javascript can
349-
# Determine the actual user ID (not username, user ID). This is
350-
# *not* a security sensitive context and it *MUST* not be used
351-
# where security matters.
352-
#
353-
# We'll also hash this value just to avoid leaking the actual User
354-
# IDs here, even though it really shouldn't matter.
355-
resp.set_cookie(
356-
USER_ID_INSECURE_COOKIE,
357-
hashlib.blake2b(
358-
str(userid).encode("ascii"), person=b"warehouse.userid"
359-
)
360-
.hexdigest()
361-
.lower(),
362-
)
347+
_set_userid_insecure_cookie(resp, userid)
363348

364349
return resp
365350

@@ -421,12 +406,7 @@ def two_factor_and_totp_validate(request, _form_class=TOTPAuthenticationForm):
421406
user_service.update_user(userid, last_totp_value=form.totp_value.data)
422407

423408
resp = HTTPSeeOther(redirect_to)
424-
resp.set_cookie(
425-
USER_ID_INSECURE_COOKIE,
426-
hashlib.blake2b(str(userid).encode("ascii"), person=b"warehouse.userid")
427-
.hexdigest()
428-
.lower(),
429-
)
409+
_set_userid_insecure_cookie(resp, userid)
430410

431411
if not two_factor_state.get("has_recovery_codes", False):
432412
send_recovery_code_reminder_email(request, request.user)
@@ -515,13 +495,7 @@ def webauthn_authentication_validate(request):
515495

516496
two_factor_method = "webauthn"
517497
_login_user(request, userid, two_factor_method, two_factor_label=webauthn.label)
518-
519-
request.response.set_cookie(
520-
USER_ID_INSECURE_COOKIE,
521-
hashlib.blake2b(str(userid).encode("ascii"), person=b"warehouse.userid")
522-
.hexdigest()
523-
.lower(),
524-
)
498+
_set_userid_insecure_cookie(request.response, userid)
525499

526500
if not request.user.has_recovery_codes:
527501
send_recovery_code_reminder_email(request, request.user)
@@ -538,6 +512,22 @@ def webauthn_authentication_validate(request):
538512
return {"fail": {"errors": errors}}
539513

540514

515+
def _set_userid_insecure_cookie(resp, userid):
516+
# We'll use this cookie so that client side javascript can
517+
# Determine the actual user ID (not username, user ID). This is
518+
# *not* a security sensitive context and it *MUST* not be used
519+
# where security matters.
520+
#
521+
# We'll also hash this value just to avoid leaking the actual User
522+
# IDs here, even though it really shouldn't matter.
523+
resp.set_cookie(
524+
USER_ID_INSECURE_COOKIE,
525+
hashlib.blake2b(str(userid).encode("ascii"), person=b"warehouse.userid")
526+
.hexdigest()
527+
.lower(),
528+
)
529+
530+
541531
def _check_remember_device_token(request, user_id) -> bool:
542532
"""
543533
Returns true if the given remember device cookie is valid for the given user.
@@ -612,12 +602,7 @@ def recovery_code(request, _form_class=RecoveryCodeAuthenticationForm):
612602
_login_user(request, userid, two_factor_method="recovery-code")
613603

614604
resp = HTTPSeeOther(request.route_path("manage.account"))
615-
resp.set_cookie(
616-
USER_ID_INSECURE_COOKIE,
617-
hashlib.blake2b(str(userid).encode("ascii"), person=b"warehouse.userid")
618-
.hexdigest()
619-
.lower(),
620-
)
605+
_set_userid_insecure_cookie(resp, userid)
621606

622607
user = user_service.get_user(userid)
623608
user.record_event(
@@ -765,9 +750,12 @@ def register(request, _form_class=RegistrationForm):
765750
send_email_verification_email(request, (user, email))
766751
email_limiter.hit(user.id)
767752

768-
return HTTPSeeOther(
753+
resp = HTTPSeeOther(
769754
request.route_path("index"), headers=dict(_login_user(request, user.id))
770755
)
756+
_set_userid_insecure_cookie(resp, user.id)
757+
758+
return resp
771759

772760
return {"form": form}
773761

warehouse/locale/messages.pot

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -144,185 +144,185 @@ msgid ""
144144
" ${ip})"
145145
msgstr ""
146146

147-
#: warehouse/accounts/views.py:390 warehouse/accounts/views.py:459
148-
#: warehouse/accounts/views.py:461 warehouse/accounts/views.py:490
149-
#: warehouse/accounts/views.py:492 warehouse/accounts/views.py:598
147+
#: warehouse/accounts/views.py:375 warehouse/accounts/views.py:439
148+
#: warehouse/accounts/views.py:441 warehouse/accounts/views.py:470
149+
#: warehouse/accounts/views.py:472 warehouse/accounts/views.py:588
150150
msgid "Invalid or expired two factor login."
151151
msgstr ""
152152

153-
#: warehouse/accounts/views.py:453
153+
#: warehouse/accounts/views.py:433
154154
msgid "Already authenticated"
155155
msgstr ""
156156

157-
#: warehouse/accounts/views.py:533
157+
#: warehouse/accounts/views.py:507
158158
msgid "Successful WebAuthn assertion"
159159
msgstr ""
160160

161-
#: warehouse/accounts/views.py:630 warehouse/manage/views/__init__.py:871
161+
#: warehouse/accounts/views.py:615 warehouse/manage/views/__init__.py:871
162162
msgid "Recovery code accepted. The supplied code cannot be used again."
163163
msgstr ""
164164

165-
#: warehouse/accounts/views.py:722
165+
#: warehouse/accounts/views.py:707
166166
msgid ""
167167
"New user registration temporarily disabled. See https://pypi.org/help"
168168
"#admin-intervention for details."
169169
msgstr ""
170170

171-
#: warehouse/accounts/views.py:888
171+
#: warehouse/accounts/views.py:876
172172
msgid "Expired token: request a new password reset link"
173173
msgstr ""
174174

175-
#: warehouse/accounts/views.py:890
175+
#: warehouse/accounts/views.py:878
176176
msgid "Invalid token: request a new password reset link"
177177
msgstr ""
178178

179-
#: warehouse/accounts/views.py:892 warehouse/accounts/views.py:993
180-
#: warehouse/accounts/views.py:1099 warehouse/accounts/views.py:1268
179+
#: warehouse/accounts/views.py:880 warehouse/accounts/views.py:981
180+
#: warehouse/accounts/views.py:1087 warehouse/accounts/views.py:1256
181181
msgid "Invalid token: no token supplied"
182182
msgstr ""
183183

184-
#: warehouse/accounts/views.py:896
184+
#: warehouse/accounts/views.py:884
185185
msgid "Invalid token: not a password reset token"
186186
msgstr ""
187187

188-
#: warehouse/accounts/views.py:901
188+
#: warehouse/accounts/views.py:889
189189
msgid "Invalid token: user not found"
190190
msgstr ""
191191

192-
#: warehouse/accounts/views.py:912
192+
#: warehouse/accounts/views.py:900
193193
msgid "Invalid token: user has logged in since this token was requested"
194194
msgstr ""
195195

196-
#: warehouse/accounts/views.py:930
196+
#: warehouse/accounts/views.py:918
197197
msgid ""
198198
"Invalid token: password has already been changed since this token was "
199199
"requested"
200200
msgstr ""
201201

202-
#: warehouse/accounts/views.py:961
202+
#: warehouse/accounts/views.py:949
203203
msgid "You have reset your password"
204204
msgstr ""
205205

206-
#: warehouse/accounts/views.py:989
206+
#: warehouse/accounts/views.py:977
207207
msgid "Expired token: request a new email verification link"
208208
msgstr ""
209209

210-
#: warehouse/accounts/views.py:991
210+
#: warehouse/accounts/views.py:979
211211
msgid "Invalid token: request a new email verification link"
212212
msgstr ""
213213

214-
#: warehouse/accounts/views.py:997
214+
#: warehouse/accounts/views.py:985
215215
msgid "Invalid token: not an email verification token"
216216
msgstr ""
217217

218-
#: warehouse/accounts/views.py:1006
218+
#: warehouse/accounts/views.py:994
219219
msgid "Email not found"
220220
msgstr ""
221221

222-
#: warehouse/accounts/views.py:1009
222+
#: warehouse/accounts/views.py:997
223223
msgid "Email already verified"
224224
msgstr ""
225225

226-
#: warehouse/accounts/views.py:1029
226+
#: warehouse/accounts/views.py:1017
227227
msgid "You can now set this email as your primary address"
228228
msgstr ""
229229

230-
#: warehouse/accounts/views.py:1032
230+
#: warehouse/accounts/views.py:1020
231231
msgid "This is your primary address"
232232
msgstr ""
233233

234-
#: warehouse/accounts/views.py:1038
234+
#: warehouse/accounts/views.py:1026
235235
#, python-brace-format
236236
msgid "Email address ${email_address} verified. ${confirm_message}."
237237
msgstr ""
238238

239-
#: warehouse/accounts/views.py:1095
239+
#: warehouse/accounts/views.py:1083
240240
msgid "Expired token: request a new organization invitation"
241241
msgstr ""
242242

243-
#: warehouse/accounts/views.py:1097
243+
#: warehouse/accounts/views.py:1085
244244
msgid "Invalid token: request a new organization invitation"
245245
msgstr ""
246246

247-
#: warehouse/accounts/views.py:1103
247+
#: warehouse/accounts/views.py:1091
248248
msgid "Invalid token: not an organization invitation token"
249249
msgstr ""
250250

251-
#: warehouse/accounts/views.py:1107
251+
#: warehouse/accounts/views.py:1095
252252
msgid "Organization invitation is not valid."
253253
msgstr ""
254254

255-
#: warehouse/accounts/views.py:1116
255+
#: warehouse/accounts/views.py:1104
256256
msgid "Organization invitation no longer exists."
257257
msgstr ""
258258

259-
#: warehouse/accounts/views.py:1168
259+
#: warehouse/accounts/views.py:1156
260260
#, python-brace-format
261261
msgid "Invitation for '${organization_name}' is declined."
262262
msgstr ""
263263

264-
#: warehouse/accounts/views.py:1231
264+
#: warehouse/accounts/views.py:1219
265265
#, python-brace-format
266266
msgid "You are now ${role} of the '${organization_name}' organization."
267267
msgstr ""
268268

269-
#: warehouse/accounts/views.py:1264
269+
#: warehouse/accounts/views.py:1252
270270
msgid "Expired token: request a new project role invitation"
271271
msgstr ""
272272

273-
#: warehouse/accounts/views.py:1266
273+
#: warehouse/accounts/views.py:1254
274274
msgid "Invalid token: request a new project role invitation"
275275
msgstr ""
276276

277-
#: warehouse/accounts/views.py:1272
277+
#: warehouse/accounts/views.py:1260
278278
msgid "Invalid token: not a collaboration invitation token"
279279
msgstr ""
280280

281-
#: warehouse/accounts/views.py:1276
281+
#: warehouse/accounts/views.py:1264
282282
msgid "Role invitation is not valid."
283283
msgstr ""
284284

285-
#: warehouse/accounts/views.py:1291
285+
#: warehouse/accounts/views.py:1279
286286
msgid "Role invitation no longer exists."
287287
msgstr ""
288288

289-
#: warehouse/accounts/views.py:1323
289+
#: warehouse/accounts/views.py:1311
290290
#, python-brace-format
291291
msgid "Invitation for '${project_name}' is declined."
292292
msgstr ""
293293

294-
#: warehouse/accounts/views.py:1389
294+
#: warehouse/accounts/views.py:1377
295295
#, python-brace-format
296296
msgid "You are now ${role} of the '${project_name}' project."
297297
msgstr ""
298298

299-
#: warehouse/accounts/views.py:1469
299+
#: warehouse/accounts/views.py:1457
300300
#, python-brace-format
301301
msgid "Please review our updated <a href=\"${tos_url}\">Terms of Service</a>."
302302
msgstr ""
303303

304-
#: warehouse/accounts/views.py:1681 warehouse/accounts/views.py:1923
304+
#: warehouse/accounts/views.py:1669 warehouse/accounts/views.py:1911
305305
#: warehouse/manage/views/__init__.py:1409
306306
msgid ""
307307
"Trusted publishing is temporarily disabled. See https://pypi.org/help"
308308
"#admin-intervention for details."
309309
msgstr ""
310310

311-
#: warehouse/accounts/views.py:1702
311+
#: warehouse/accounts/views.py:1690
312312
msgid "disabled. See https://pypi.org/help#admin-intervention for details."
313313
msgstr ""
314314

315-
#: warehouse/accounts/views.py:1718
315+
#: warehouse/accounts/views.py:1706
316316
msgid ""
317317
"You must have a verified email in order to register a pending trusted "
318318
"publisher. See https://pypi.org/help#openid-connect for details."
319319
msgstr ""
320320

321-
#: warehouse/accounts/views.py:1731
321+
#: warehouse/accounts/views.py:1719
322322
msgid "You can't register more than 3 pending trusted publishers at once."
323323
msgstr ""
324324

325-
#: warehouse/accounts/views.py:1746 warehouse/manage/views/__init__.py:1590
325+
#: warehouse/accounts/views.py:1734 warehouse/manage/views/__init__.py:1590
326326
#: warehouse/manage/views/__init__.py:1705
327327
#: warehouse/manage/views/__init__.py:1819
328328
#: warehouse/manage/views/__init__.py:1931
@@ -331,29 +331,29 @@ msgid ""
331331
"again later."
332332
msgstr ""
333333

334-
#: warehouse/accounts/views.py:1756 warehouse/manage/views/__init__.py:1603
334+
#: warehouse/accounts/views.py:1744 warehouse/manage/views/__init__.py:1603
335335
#: warehouse/manage/views/__init__.py:1718
336336
#: warehouse/manage/views/__init__.py:1832
337337
#: warehouse/manage/views/__init__.py:1944
338338
msgid "The trusted publisher could not be registered"
339339
msgstr ""
340340

341-
#: warehouse/accounts/views.py:1771
341+
#: warehouse/accounts/views.py:1759
342342
msgid ""
343343
"This trusted publisher has already been registered. Please contact PyPI's"
344344
" admins if this wasn't intentional."
345345
msgstr ""
346346

347-
#: warehouse/accounts/views.py:1798
347+
#: warehouse/accounts/views.py:1786
348348
msgid "Registered a new pending publisher to create "
349349
msgstr ""
350350

351-
#: warehouse/accounts/views.py:1936 warehouse/accounts/views.py:1949
352-
#: warehouse/accounts/views.py:1956
351+
#: warehouse/accounts/views.py:1924 warehouse/accounts/views.py:1937
352+
#: warehouse/accounts/views.py:1944
353353
msgid "Invalid publisher ID"
354354
msgstr ""
355355

356-
#: warehouse/accounts/views.py:1963
356+
#: warehouse/accounts/views.py:1951
357357
msgid "Removed trusted publisher for project "
358358
msgstr ""
359359

0 commit comments

Comments
 (0)