add confirmation via unique link

This commit is contained in:
pstruebi
2022-06-14 17:35:52 +02:00
parent e287a09e1b
commit 4518f0b290
7 changed files with 48 additions and 28 deletions

47
auth.py
View File

@@ -1,4 +1,6 @@
from datetime import datetime
import functools
import logging
from django import db
from flask import (
@@ -8,8 +10,8 @@ from werkzeug.security import check_password_hash, generate_password_hash
from itsdangerous import URLSafeTimedSerializer
from db import get_db
from app import app
import app
import calendar_interface
bp = Blueprint('auth', __name__, url_prefix='/auth')
@@ -29,6 +31,7 @@ def register():
error = 'Password is required.'
elif not email:
error = 'Email is required.'
# TODO: check passwrd complexity
if error is None:
try:
@@ -37,10 +40,19 @@ def register():
(username, email, generate_password_hash(password)),
)
db.commit()
except db.IntegrityError:
error = f"User mit email {email} existiert bereits."
else:
return redirect(url_for("auth.login"))
token = generate_confirmation_token(email)
confirm_url = url_for('auth.confirm_email', token=token, _external=True)
logging.info("Generated confirmation url: %s", confirm_url)
content = render_template('auth/confirm_mail.html', confirm_url=confirm_url, username=username, email=email)
subject = "Registrierung für Planner von %s" % email
calendar_interface.send_mail("struebin.patrick@gmail.com", subject, content)
flash("Registrierung erfolgreich.")
return redirect(url_for("index"))
flash(error)
@@ -96,6 +108,7 @@ def login_required(view): # use this as decorator
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None:
flash("Benutzer bitte anmelden.")
return redirect(url_for('auth.login'))
elif not g.user["confirmed"]:
flash("Benutzer noch nicht freigeschaltet.")
@@ -107,17 +120,17 @@ def login_required(view): # use this as decorator
def generate_confirmation_token(email):
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
return serializer.dumps(email, salt=app.config['SECURITY_PASSWORD_SALT'])
serializer = URLSafeTimedSerializer(app.app.config['SECRET_KEY'])
return serializer.dumps(email, salt=app.app.config['SECURITY_PASSWORD_SALT'])
def confirm_token(token, expiration=3600):
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
def confirm_token(token, expiration=3600*14*28): # 2 Wochen expiration
serializer = URLSafeTimedSerializer(app.app.config['SECRET_KEY'])
try:
email = serializer.loads(
token,
salt=app.config['SECURITY_PASSWORD_SALT'],
# max_age=expiration
salt=app.app.config['SECURITY_PASSWORD_SALT'],
max_age=expiration
)
except:
return False
@@ -125,22 +138,22 @@ def confirm_token(token, expiration=3600):
@bp.route('/confirm/<token>')
@login_required
# @login_required # TODO: notwendig? security ?
def confirm_email(token):
try:
email = confirm_token(token)
except:
flash('The confirmation link is invalid or has expired.', 'danger')
outcome = 'The confirmation link is invalid or has expired.'
if g.user["confirmed"]:
flash('Account already confirmed. Please login.', 'success')
outcome = 'Account already confirmed.'
else:
db = get_db()
db.execute(
"UPDATE user SET confirmed = '1' where email = ?",
(email,)
"UPDATE user SET confirmed = '1', confirmation_date = ? where email = ?",
(str(datetime.now()), email)
)
db.commit()
outcome= "User wurde erfolgreich freigeschaltet."
flash('You have confirmed your account. Thanks!', 'success')
return redirect(url_for('main.home'))
return render_template('auth/confirmation_successful.html', email=email, outcome=outcome)

View File

@@ -85,10 +85,7 @@ def execute_patch_request(token, endpoint, data):
def send_mail(to, subject, content, user_id=USER_ID):
token=get_access_token()
with open("templates/auth/activate.html") as f:
content=f.read()
mail = {
"message": {
"subject": subject,

View File

@@ -5,5 +5,6 @@ CREATE TABLE user (
username TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
confirmed BOOLEAN DEFAULT FALSE
confirmed BOOLEAN DEFAULT FALSE,
confirmation_date TEXT
);

View File

@@ -1,4 +0,0 @@
<p>Welcome! Thanks for signing up. Please follow this link to activate your account:</p>
<p><a href="{{ confirm_url }}">{{ confirm_url }}</a></p>
<br>
<p>Cheers!</p>

View File

@@ -0,0 +1,6 @@
<p>{{username}} with email {{email}} wants to be confirmed.</p>
<p>follow this link only if the user can be trusted to activate the account:</p>
<p><a href="{{ confirm_url }}"> {{ confirm_url }}
</a></p>
<br>
<p>Cheers!</p>

View File

@@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %}Benutzer mit email: {{email}}.{% endblock %}</h1>
<h1>{% block title %}{{outcome}}.{% endblock %}</h1>
{% endblock %}

View File

@@ -6,10 +6,10 @@
{% block content %}
<form method="post">
<label for="email">Email (Account login)</label>
<input type="email" name="email" id="email" required>
<label for="username">Name</label>
<input name="username" id="username" required>
<label for="email">Email</label>
<input type="email" name="email" id="email" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Register">