Skip to content

Commit 3963a7f

Browse files
authored
Prevent linkbots from consuming tokens in one time links (#4775)
Fixes #4535 OBS! `PASSWORD_RESET_TIMEOUT` have a new sane default of 15 minutes. A new timeout setting `PASSWORD_ACTIVATION_TIMEOUT` was added that also default to 15 minutes. `PASSWORD_RESET_TIMEOUT` used to default to 3 days to allow new users some time to activate their account. Organisation that still want the old default for activation mails can set `PASSWORD_ACTIVATION_TIMEOUT = 259200`. This is mainly a fix for MS Outlook mail system habit of doing a preview of links in all e-mails. This preview expires the one time links so when a user tries to login or reset their password it does not work. The solution is to show an extra confirmation screen with a login button, so users need to click one extra time. This solves the MicrosoftPreview issue and should work for any similar issues as well. During the work I found a number of inconsistencies in various login related templates that I also attempted to fix. That is the reson so many files are changes in this PR. ## Test Steps - [ ] Use the signup and passwordless login and confirm that you by clicking the link in the email come to a confirmation screen. Clicking the button there log you in to the site.
1 parent 32c40a7 commit 3963a7f

26 files changed

Lines changed: 293 additions & 184 deletions

docs/setup/administrators/configuration.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,18 @@ The corresponding locale dir is named: en, en_GB, en_US
4848

4949
----
5050

51-
Number of seconds that password reset and account activation links are valid (default 259200, 3 days).
51+
Number of seconds that password reset links are valid (default 259200, 3 days).
5252

5353
PASSWORD_RESET_TIMEOUT = env.int('PASSWORD_RESET_TIMEOUT', 259200)
5454

5555
----
5656

57+
Number of seconds that account activation links are valid (default 900, 15 minutes).
58+
59+
PASSWORD_ACTIVATION_TIMEOUT = env.int("PASSWORD_ACTIVATION_TIMEOUT", 900)
60+
61+
----
62+
5763
Seconds to enter password on password page while email change/2FA change (default 120).
5864

5965
PASSWORD_PAGE_TIMEOUT = env.int('PASSWORD_PAGE_TIMEOUT', 120)

hypha/apply/users/templates/two_factor/_base.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
{{ block.super }}
2929
{# Focus the 2FA field. #}
3030
<script>
31-
document.querySelector("#id_generator-token").focus();
31+
const generatorToken = document.querySelector("#id_generator-token");
32+
if (generatorToken) {
33+
generatorToken.focus();
34+
}
3235
</script>
3336
{% endblock %}

hypha/apply/users/templates/two_factor/core/backup_tokens.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
{% load static i18n users_tags heroicons %}
33

44
{% block content_inner %}
5-
<h1 class="mb-2 font-semibold text-h2">
5+
<h2 class="mb-2 font-semibold text-h2">
66
{% block title %}{% trans "Backup Codes" %}{% endblock %}
7-
</h1>
7+
</h2>
88

99
<p class="mb-2 print:!hidden">
1010
{% blocktrans %}You should now print these codes or copy them to your

hypha/apply/users/templates/two_factor/core/backup_tokens_password.html

Lines changed: 0 additions & 42 deletions
This file was deleted.

hypha/apply/users/templates/two_factor/core/setup_complete.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
{% load i18n %}
33

44
{% block content_inner %}
5-
65
<div class="mb-4 prose">
76
<p>{% blocktrans trimmed %}Congratulations, you've successfully enabled two-factor
87
authentication.{% endblocktrans %}</p>
@@ -31,5 +30,4 @@
3130
</a>
3231
{% endif %}
3332
</div>
34-
3533
{% endblock %}

hypha/apply/users/templates/two_factor/core/two_factor_required.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
{% extends "two_factor/_base.html" %}
33
{% load i18n %}
44

5-
{% block content %}
6-
<h1>{% block title %}{% trans "Permission Denied" %}: {{ reason }}{% endblock %}</h1>
5+
{% block content_inner %}
6+
<h2 class="mb-2 text-h2">{% block title %}{% trans "Permission Denied" %}: {{ reason }}{% endblock %}</h2>
77

88
<div class="mb-4 prose">
99
<p>

hypha/apply/users/templates/two_factor/profile/disable.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
{% block content_inner %}
55

6-
<h1>{% block title %}{% trans "Disable Two-factor Authentication" %}{% endblock %}</h1>
7-
<p class="mb-4">{% blocktrans trimmed %}Disabling Two-factor authentication weakens your account security.
6+
<h1 class="mb-2 text-h1">{% block title %}{% trans "Disable Two-factor Authentication" %}{% endblock %}</h1>
7+
<p class="mb-4 whitespace-normal label">{% blocktrans trimmed %}Disabling Two-factor authentication weakens your account security.
88
We recommend reenabling it when you can.{% endblocktrans %}</p>
99

1010
<form class="form" action="" method="POST" novalidate>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{% extends "base-apply.html" %}
2+
{% load i18n heroicons %}
3+
4+
{% block title %}{% if is_signup or is_activation %}{% trans "Confirm account creation" %}{% else %}{% trans "Confirm login" %}{% endif %}{% endblock %}
5+
{% block body_class %}bg-base-200{% endblock %}
6+
7+
{% block content %}
8+
<div class="flex flex-col justify-center items-center min-h-[60vh]">
9+
<section class="w-full max-w-2xl card shadow-xs bg-base-100 md:card-lg">
10+
<div class="items-center card-body">
11+
<span class="flex justify-center items-center mb-4 rounded-full bg-primary/10">
12+
{% heroicon_outline "key" aria_hidden="true" size=64 %}
13+
</span>
14+
15+
<h1 class="mb-4 font-semibold text-h0">
16+
{% if is_signup or is_activation %}
17+
{% trans "Complete your registration" %}
18+
{% else %}
19+
{% trans "Complete your login" %}
20+
{% endif %}
21+
</h1>
22+
23+
<div class="mb-6 prose">
24+
{% if is_signup or is_activation %}
25+
<p>{% trans "Your activation link is valid. Click the button below to create your account." %}</p>
26+
{% else %}
27+
<p>{% trans "Your login link is valid. Click the button below to complete your login." %}</p>
28+
{% endif %}
29+
</div>
30+
31+
<form method="post">
32+
{% csrf_token %}
33+
{% if remember_me %}
34+
<input type="hidden" name="remember_me" value="1">
35+
{% endif %}
36+
{% if next %}
37+
<input type="hidden" name="next" value="{{ next }}">
38+
{% endif %}
39+
<button type="submit" class="btn btn-primary btn-lg">
40+
{% if is_signup or is_activation %}
41+
{% trans "Create my account" %}
42+
{% else %}
43+
{% trans "Log in" %}
44+
{% endif %}
45+
</button>
46+
</form>
47+
</div>
48+
</section>
49+
</div>
50+
{% endblock %}

hypha/apply/users/templates/users/activation/email.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
{% if site %}{{ site.root_url }}{% else %}{{ base_url }}{% endif %}{{ activation_path }}
77

8-
{% blocktrans %}This link can be used only once and will lead you to a page where you can set your password. It will remain active for {{ timeout_days }} days, so please set your password as soon as possible.{% endblocktrans %}
8+
{% blocktrans %}This link can be used only once and will lead you to a page where you can set your password. It will remain active for {{ timeout_minutes }} minutes, so please set your password as soon as possible.{% endblocktrans %}
99

1010
{% trans "After setting your password, you will be able to log in at" %}: {% if site %}{{ site.root_url }}{% else %}{{ base_url }}{% endif %} {% trans "in the future using" %}:
1111

1212
{% trans "Username" %}: {{ username }}
1313
{% trans "Password" %}: {% trans "Your chosen password" %}
1414

15-
{% blocktrans %}If you do not complete the activation process within {{ timeout_days }} days you can use the password reset form at{% endblocktrans %}: {% if site %}{{ site.root_url }}{% else %}{{ base_url }}{% endif %}{% url 'users:password_reset' %}
15+
{% blocktrans %}If you do not complete the activation process within {{ timeout_minutes }} minutes you can use the password reset form at{% endblocktrans %}: {% if site %}{{ site.root_url }}{% else %}{{ base_url }}{% endif %}{% url 'users:password_reset' %}
1616

1717
{% blocktrans %}Kind Regards,
1818
The {{ ORG_SHORT_NAME }} Team{% endblocktrans %}

hypha/apply/users/templates/users/activation/invalid.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% extends "base-apply.html" %}
22
{% load i18n heroicons %}
33

4-
{% block title %}{% trans "Activation link issue" %}{% endblock %}
4+
{% block title %}{% trans "One time link issue" %}{% endblock %}
55
{% block body_class %}bg-base-200{% endblock %}
66

77
{% block content %}
@@ -12,12 +12,12 @@
1212
{% heroicon_outline "exclamation-triangle" class="w-14 h-14 text-warning" %}
1313
</span>
1414

15-
<h2 class="mb-4 font-semibold text-h0">{% trans "We couldn't activate your account" %}</h2>
15+
<h1 class="mb-4 font-semibold text-h0">{% trans "The one time link has expired" %}</h1>
1616

1717
<div class="prose">
1818
{% url 'users:password_reset' as password_reset %}
1919

20-
<p>{% trans "This usually happens because your activation link has expired, or your account is already activated." %}</p>
20+
<p>{% trans "This usually happens because your one time link has expired, or your account is already activated." %}</p>
2121

2222
<p>
2323
{% blocktrans %}Try <a href="{{ password_reset }}">resetting your password</a> first. If you're still having trouble, contact us at {{ ORG_SHORT_NAME }}:{% endblocktrans %}

0 commit comments

Comments
 (0)