Autoregister on comment

This commit is contained in:
David Hoppenbrouwers
2022-10-15 22:35:47 +02:00
parent 17844fa11c
commit eafa141a2f
5 changed files with 82 additions and 30 deletions

View File

@@ -432,7 +432,7 @@ class DB:
return c.execute('''
select user_id
from users
where name = ?
where name = lower(?)
''',
(username,)
).fetchone()

45
main.py
View File

@@ -234,12 +234,19 @@ def delete_thread(thread_id):
# TODO return 403, maybe?
return redirect(url_for('index'))
def _add_comment_check_user():
user_id = session.get('user_id')
if user_id is not None:
return user_id
if not config.registration_enabled:
flash('Registrations are not enabled. Please log in to comment', 'error')
if register_user(True):
return session['user_id']
@app.route('/thread/<int:thread_id>/comment/', methods = ['POST'])
def add_comment(thread_id):
user_id = session.get('user_id')
if user_id is None:
return redirect(url_for('login'))
user_id = _add_comment_check_user()
if user_id is not None:
text = trim_text(request.form['text'])
if text == '':
flash('Text may not be empty', 'error')
@@ -251,10 +258,8 @@ def add_comment(thread_id):
@app.route('/comment/<int:comment_id>/comment/', methods = ['POST'])
def add_comment_parent(comment_id):
user_id = session.get('user_id')
if user_id is None:
return redirect(url_for('login'))
user_id = _add_comment_check_user()
if user_id is not None:
text = trim_text(request.form['text'])
if text == '':
flash('Text may not be empty', 'error')
@@ -358,8 +363,7 @@ def edit_comment(comment_id):
def register():
if request.method == 'POST':
username, passwd = request.form['username'], request.form['password']
if register_user():
flash('Account has been created', 'success')
if register_user(False):
return redirect(url_for('index'))
capt, answer = captcha.generate(config.captcha_key)
@@ -700,7 +704,7 @@ def get_user():
return User(id, name, role, banned_until)
return None
def register_user():
def register_user(show_password):
username, passwd = request.form['username'], request.form['password']
if any(c in username for c in string.whitespace):
# This error is more ergonomic in case someone tries to play tricks again :)
@@ -720,6 +724,10 @@ def register_user():
if uid is None:
flash('Failed to create account (username may already be taken)', 'error')
else:
s = 'Account has been created.'
if show_password:
s += f' Your password is <code class=spoiler>{passwd}</code> (hover to reveal).'
flash(s, 'success')
uid, = uid
session['user_id'] = uid
return True
@@ -774,11 +782,26 @@ def utility_processor():
def format_time(t):
return datetime.utcfromtimestamp(t / 10 ** 9).replace(microsecond=0)
def rand_password():
'''
Generate a random password.
The current implementation returns 12 random lower- and uppercase alphabet characters.
This gives up to `log((26 * 2) ** 12) / log(2) = ~68` bits of entropy, which should be
enough for the foreseeable future.
'''
return ''.join(string.ascii_letters[secrets.randbelow(52)] for _ in range(12))
def gen_captcha():
return captcha.generate(config.captcha_key)
return {
'format_since': format_since,
'format_time': format_time,
'format_until': format_until,
'minimd': minimd.html,
'rand_password': rand_password,
'gen_captcha': gen_captcha,
}

View File

@@ -129,3 +129,12 @@ table.form > * > tr > td, th {
.small {
font-size: 85%;
}
.spoiler {
background-color: black;
color: black;
}
.spoiler:hover {
opacity: 1;
color: white;
}

View File

@@ -34,7 +34,11 @@
<main>
<h1>{{ title }}</h1>
{%- for category, msg in get_flashed_messages(True) -%}
<p class="flash {{ category }}">{{ msg }}</p>
{#-
FIXME ensure all flash() messages are free of XSS vectors.
In particular, check places where we flash error messages.
-#}
<p class="flash {{ category }}">{{ msg | safe }}</p>
{%- endfor -%}
{%- block content %}{% endblock -%}
</main>

View File

@@ -57,10 +57,26 @@
{%- endmacro -%}
{%- macro reply() -%}
{%- if user is not none and not user.is_banned() -%}
{%- if user is none -%}
{%- if config.registration_enabled -%}
<form method="post" action="comment/">
<p><textarea name="text"></textarea></p>
<p><input type="submit" value="Post comment"></p>
<p><textarea name=text></textarea></p>
{#-
Using the password generator for usernames should be sufficient to ensure it is unique.
If not, it means the password generator is broken and *must* be fixed.
-#}
<input type=text name=username value="{{ rand_password() }}" hidden>
<input type=password name=password value="{{ rand_password() }}" hidden>
{% set q, a = gen_captcha() %}
<p>Captcha: {{ q }} <input type=text name=captcha></p>
<input type=text name=answer value="{{ a }}" hidden>
<p><input type=submit value="Register & post comment"> (<a href="{{ url_for('login') }}">I already have an account</a>)</p>
</form>
{%- endif -%}
{%- elif not user.is_banned() -%}
<form method="post" action="comment/">
<p><textarea name="text"></textarea></p>
<p><input type="submit" value="Post comment"></p>
</form>
{%- endif -%}
{%- endmacro -%}