from datetime import datetime import functools import logging from flask import ( Blueprint, flash, g, redirect, render_template, request, session, url_for, current_app ) from werkzeug.security import check_password_hash, generate_password_hash from itsdangerous import URLSafeTimedSerializer from db import get_db import calendar_interface bp = Blueprint('auth', __name__, url_prefix='/auth') @bp.route('/register', methods=('GET', 'POST')) def register(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] email = request.form['email'] db = get_db() error = None if not username: error = 'Username is required.' elif not password: error = 'Password is required.' elif not email: error = 'Email is required.' elif password.lower()== password or password.upper()==password or password.isdigit() or len(password)<=8: #check passwrd complexity error = 'Bedingungen für passwort nicht erfüllt.' if error is None: try: db.execute( "INSERT INTO user (username, email, password) VALUES (?, ?, ?)", (username, email, generate_password_hash(password)), ) db.commit() except db.IntegrityError: error = f"User mit email {email} existiert bereits." else: 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 ProPedal - Planner von %s" % email # Send confirmation email to a defined static confirmation add, if not defined use the users add confirmation_add = current_app.config.get("CONFIRMATATION_EMAIL_ADD", email) calendar_interface.send_mail(confirmation_add, subject, content) flash("Registrierung erfolgreich. Auf Freischaltung warten.") return redirect(url_for("index")) flash(error) return render_template('auth/register.html') @bp.route('/login', methods=('GET', 'POST')) def login(): if request.method == 'POST': password = request.form['password'] email = request.form['email'] db = get_db() error = None user = db.execute( 'SELECT * FROM user WHERE email = ?', (email,) ).fetchone() if user is None: error = 'Email existiert nicht.' elif not check_password_hash(user['password'], password): error = 'Incorrect password.' if error is None: session.clear() session['user_id'] = user['id'] return redirect(url_for('index')) flash(error) return render_template('auth/login.html') @bp.before_app_request def load_logged_in_user(): user_id = session.get('user_id') if user_id is None: g.user = None else: g.user = get_db().execute( 'SELECT * FROM user WHERE id = ?', (user_id,) ).fetchone() @bp.route('/logout') def logout(): session.clear() return redirect(url_for('auth.login')) 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.") return redirect(url_for('auth.login')) return view(**kwargs) return wrapped_view def generate_confirmation_token(email): serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) return serializer.dumps(email, salt=current_app.config['SECURITY_PASSWORD_SALT']) def confirm_token(token, expiration=3600*14*28): # 2 Wochen expiration serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) try: email = serializer.loads( token, salt=current_app.config['SECURITY_PASSWORD_SALT'], max_age=expiration ) except: return False return email @bp.route('/confirm/') def confirm_email(token): try: email = confirm_token(token) except: outcome = 'The confirmation link is invalid or has expired.' if g.user["confirmed"]: outcome = 'Account already confirmed.' else: db = get_db() db.execute( "UPDATE user SET confirmed = '1', confirmation_date = ? where email = ?", (str(datetime.now()), email) ) db.commit() outcome= "User wurde erfolgreich freigeschaltet." return render_template('auth/confirmation.html', email=email, outcome=outcome)